Blog — testing in R and Shiny

Behavior-Driven Development in R Shiny: A Step-By-Step Example

Testing your Shiny applications shouldn't be an afterthought.

Many developers write tests after building features, missing the core benefit of test-first development: tests as design tools. I'll walk you through how I built a small content submission form using Behavior-Driven Development (BDD), starting from absolutely nothing.

Whether you're building a new app or adding a feature, the steps are the same.

Follow along and see how tests drive design decisions, keep business value visible, and make refactoring safe.

Level-up your testing game! Grab your copy of the R testing roadmap.

1. Writing the First Specification

The app's purpose we're about to build is to submit data that another app will display.

BDD starts with a high-level specification describing the behavior we want to see. The first specification is the most important. It describes the core behavior that delivers value to users.

We have 2 choices for writing specifications:

  1. In R, using testthat. We have a full freedom to design our own domain-specific language (DSL) for expressing specifications.
  2. In Gherkin syntax, using cucumber. We are constra
bddrshinyshinytest2tests
13 min read

Behavior-Driven Development in R Shiny: Modeling User Behavior with When Steps

Learn how to write When steps that describe user actions without leaking implementation details. Build a clean DSL that survives UI refactors and keeps specifications readable.

bddrshinyshinytest2tests
11 min read

Behavior-Driven Development in R Shiny: Setting Up Test Preconditions with Given Steps

Learn how to set up test preconditions in Shiny BDD using Given steps. Master dependency injection, test doubles, and composable setup patterns for reliable R testing.

bddrshinyshinytest2tests
10 min read
Topics

11 Test Smells That Make Your Tests Lie to You

Learn to recognize problems in R test code that cause your test suite to pass while hiding real bugs. Detect those issues and start writing more trustworthy tests.

rtests
22 min read

Behavior-Driven Development in R Shiny: Asserting Outcomes with Then Steps

Learn how to write Then steps that assert outcomes without coupling to implementation. Build custom testthat expectations and keep your BDD assertions at the right level.

bddrshinyshinytest2tests
7 min read

Behavior-Driven Development in R Shiny: Modeling User Behavior with When Steps

Learn how to write When steps that describe user actions without leaking implementation details. Build a clean DSL that survives UI refactors and keeps specifications readable.

bddrshinyshinytest2tests
11 min read

muttest 0.2.0: More Mutators, Better Reporting, and Parallel Execution

Expanded mutator library, improved reporting, and parallel execution for mutation testing in R.

mutation testingrtests
8 min read

Behavior-Driven Development in R Shiny: Setting Up Test Preconditions with Given Steps

Learn how to set up test preconditions in Shiny BDD using Given steps. Master dependency injection, test doubles, and composable setup patterns for reliable R testing.

bddrshinyshinytest2tests
10 min read

Simplifying Interactions with Complex Widgets in shinytest2 Using JavaScript APIs

When shinytest2's `set_inputs()` won't work, leverage widget APIs directly. Learn to write cleaner, faster and more robust tests using JavaScript APIs.

rshinyshinytest2tests
5 min read

Behavior-Driven Development in R Shiny: A Step-By-Step Example

Follow each step as I develop a form with Shiny and Behavior-Driven Development. Learn practical techniques for better software design through automated tests.

bddrshinyshinytest2tests
13 min read

Deploy Multiple Shiny Apps from One R Package

Code organization and deployment strategy for multiple Shiny apps sharing common logic within a single R package. Structuring your project in a monorepo format.

deploymentrshiny
4 min read

The Cadence of Behavior-Driven Development

Learn how to effectively implement Behavior-Driven Development (BDD) practices in your projects. Focus on delivering the most valuable scenarios first and avoid the pitfalls of over-specification.

bddrtests
6 min read

Clean R Tests with `local_mocked_bindings` and Dependency Wrapping

Learn how to write reliable R tests by wrapping external dependencies and using `testthat::local_mocked_bindings`. Make your tests fast, clean, and predictable.

rtests
6 min read

R6 Interfaces For Backend: Define What, Not How

A Practical Guide to Faking External Dependencies and Business Logic with R6 Classes for Reliable Tests.

rshinytests
5 min read

How to Write Robust shinytest2 Tests for R Shiny Apps

A step-by-step guide to stronger R Shiny testing with stable selectors and reusable actions.

rshinyshinytest2tests
5 min read

How to Test R Code That Uses LLMs, APIs, or Databases

A Practical Guide to Faking External Dependencies in R for Fast, Reliable Tests.

llmrtests
3 min read

How to Write Cucumber Specifications the Right Way: From App Description to Scenarios

Adding Cucumber specifications to an existing application? Learn how to write Gherkin scenarios that focus on user behavior, not implementation details. Use AI to iterate faster.

bddcucumberllmrshinytests
5 min read

Refactoring Cucumber and Playwright Acceptance Tests with GitHub Copilot

Given a set of existing Cucumber and Playwright acceptance tests, I asked Copilot to refactor them according to best practices for step organization and anti-patterns.

bddcucumberllmrtests
5 min read

3 Reasons Blocking You From Doing Automated Testing

Get them out of your way to start testing your code effectively.

rtests
4 min read

Testing your Plumber APIs from R

Learn how to effectively test your Plumber APIs in R using a two-layer testing strategy that separates business logic from API contracts.

plumberrtests
6 min read

Testing Legacy Shiny Apps: Start with Behavior, Not Code

Adding acceptance tests first makes refactoring safer.

rtests
4 min read

The 4 Layers of Testing Every R Package Needs

Discover the essential layers of testing for robust R packages: unit tests, acceptance tests, code coverage, and mutation testing.

rtests
3 min read

An Introduction to Behavior-Driven Development in R

Learn how to use Behavior-Driven Development (BDD) in R to ensure your software meets user requirements through executable specifications.

bddcucumberrtests
8 min read

Keys To Scalable Code: Owning The Interfaces You Use

Learn how to build scalable and maintainable code by abstraction and information hiding, improving flexibility and ease of future changes.

rshiny
4 min read

Acceptance Test-Driven Development with Shiny

Learn how to apply Acceptance Test-Driven Development (ATDD) to build robust Shiny applications using {shinytest2} and {selenider}.

rshinytests
2 min read

Maximizing Efficiency with AI-Assisted Testing: Lessons Learned

Discover the benefits and challenges of AI-assisted testing, and learn how to optimize your testing process for better code quality and maintainability.

rtests
3 min read

Efficient Snapshot Testing in R with CI and GitHub API

Learn how to manage snapshot tests in R using CI and GitHub API to ensure consistency across different environments.

rtests
5 min read

How to Get Code Coverage Reports Without Sharing Code with Codecov.io

Learn how to generate code coverage reports in R using cobertura-action without sharing your private code with codecov.io.

rtests
2 min read

Essential BDD Playlist: Master Behavior-Driven Development with Dave Farley

Discover how to build user-focused software with BDD. Learn from Dave Farley's comprehensive YouTube series.

bddresourcetests
2 min read

Choosing the Best Library for Acceptance Testing Shiny Apps: {shinytest2} vs Cypress

Compare {shinytest2} and Cypress for acceptance testing Shiny apps. Learn their pros, cons, and which might suit your project better.

rtests
5 min read

Understanding Software Quality: Unit Tests vs Acceptance Tests

Learn the differences between unit tests and acceptance tests and how they contribute to software quality.

bddtests
1 min read

The Benefits of Writing Good Automated Tests

Learn how good automated tests can save time, reduce costs, and improve software quality.

tests
2 min read

The Consequences of Poor Test Writing in Software Development

Learn how poor test writing can halt your development process and discover strategies to avoid this pitfall.

tests
2 min read

Optimize Your Unit Test Structure for Faster Feedback

Learn how to speed up your unit tests by optimizing the structure of your test files using testthat in R.

rtddtests
3 min read

How Tests Improve Code Quality: 3 Key Insights

Discover how tests can reveal code modularity, coupling, and separation of concerns to improve your code quality.

rtests
6 min read

Top 3 Testing Lessons from 3 Years as an R Developer

Discover the top three lessons learned from three years of testing as an R developer. Improve your testing practices with these insights.

rtests
5 min read

Improve Your Unit Test Titles for Better Code Understanding

Learn how to write descriptive unit test titles that enhance code readability and maintainability.

rtests
4 min read

How to Easily Capture and Test Code Output in R

Learn methods to capture and test code output in R, including snapshot testing, dput, and constructive package.

rtests
5 min read

Optimize Shinytest2: Speed Up Your Shiny App Tests

Learn how to speed up Shiny app tests using shinytest2 by reusing application instances and refreshing the browser.

rshinyshinytest2tddtests
8 min read

Effective Testing of Shiny Components with shinytest2

Learn how to test Shiny components for correct markup and server communication using shinytest2.

rtests
4 min read

Effective State Management in Shiny Modules: A React-Inspired Approach

Learn how to manage state in Shiny modules using a React-inspired approach with event handlers for better control and flexibility.

rshiny
5 min read

Creating Robust E2E Test Selectors for Shiny Apps

Learn how to create resilient E2E test selectors in Shiny apps using data-* attributes and best practices.

rshinytestsui
3 min read

How to Snapshot Test Excel Workbooks in Shiny Apps

Learn how to export data to Excel in Shiny apps and use snapshot tests to validate and inspect the exported workbooks.

rshinytddtests
4 min read

Developing Shiny Modules with Test-Driven Development

Learn how to use tests to develop Shiny modules efficiently, ensuring faster development cycles and better modularization.

rshinytddtests
3 min read

How to Set Up Cucumber for End-to-End Testing in Rhino Projects

Learn how to set up Cucumber with Cypress in Rhino projects for clear and maintainable end-to-end tests.

rshinytests
5 min read

BDD Style Testing for Shiny Module Servers with R6 and testServer

Learn how to write BDD style tests for Shiny module servers using R6 and testServer to improve readability and maintainability.

rshinytests
5 min read

Real-Time Input Validation Using Bootstrap Form Validation API

Learn how to implement real-time input validation in Shiny apps using Bootstrap Form Validation API for immediate feedback.

rshinyui
2 min read

How to Use Acceptance Test-Driven Development for Shiny Modules

Learn how to apply acceptance test-driven development (ATDD) to build robust Shiny modules with R6 and shinytest2.

rshinytests
2 min read

Understanding Agile Testing Quadrants for Effective Software Testing

Learn about Agile Testing Quadrants and how they help in planning and executing different types of tests in software development.

tests
3 min read

Comprehensive Guide to Testing Shiny Modules with shiny::testServer

Learn how to effectively test Shiny modules using shiny::testServer with examples and best practices.

rshinytests
3 min read

3-Step Guide to Building Plots Faster with Test Driven Development

Discover how to use TDD and approval testing to rapidly develop and test plots in R.

rtddtestsui
5 min read

How Test-Driven Development (TDD) Speeds Up Prototyping

Learn how TDD helps you prototype faster by allowing you to experiment with your code and find better solutions quickly.

rtddtests
3 min read

Extending Shiny Modules with TDD in Legacy Code

Learn how to extend Shiny modules in legacy code using the Sprout Technique and Test Driven Development.

rshinytddtests
1 min read

How to Develop Quickly Using a New Library Without Reading Extensive Documentation

Learn how to use AI tools to use new libraries quickly without spending hours on documentation.

llmrtests
3 min read

How to Test Code with External Dependencies Using Stubs in R

Learn how to test R functions with external dependencies using stubs and the testthat package.

rtests
2 min read

Mastering Test-Driven Development: 3 Essential Steps for Better Code

Learn the 3 essential steps of Test-Driven Development (TDD) to improve code quality and development speed.

rtddtests
3 min read

Mastering Test Driven Development: Build the Right Thing First

Learn how Test Driven Development (TDD) ensures you build the right thing on the first try with no rewrites.

rtddtests
2 min read

Effective Strategies to Avoid Frustration with Legacy Code

Learn how to manage legacy code efficiently using the Sprout Technique to reduce frustration and improve productivity.

rtests
2 min read

Improve Your Unit Tests with Arrange, Act, Assert Method

Learn how to write cleaner and more effective unit tests using the Arrange, Act, Assert method. Step-by-step guide with examples.

rtests
4 min read

How We Achieved 96% Code Coverage in a 2-Week App Prototype

Learn how we built an app prototype with 96% code coverage in just 2 weeks using TDD and effective testing strategies.

rshinytddtests
5 min read

3 Essential Types of Unit Tests Every R Developer Should Know

Learn about Direct Response, State Change, and Interaction Tests to improve your unit testing strategy.

rtests
3 min read