Write scenarios in Gherkin syntax to describe the behavior of your system.
Use Given, When, Then keywords to shape your specifications clearly.
Feature: Sales Trends
Scenario: User views the sales trend for a product category
Given the user can view product sales information
When they view the sales trend for "Electronics"
Then they should see the sales trend plot for "Electronics"
Scenario: User views the sales trend for a specific product
Given the user can view product sales information
When they view the sales trend for "Smartphone"
Then they should see the sales trend plot for "Smartphone"
Write implmementaion for steps in scenarios as R functions.
Whether it's a package, a Shiny app, or an API – simulate Users interactions with your code.
library(cucumber)
given("the user can view product sales information", function(context) {
# View product sales information
)}
when("they view the sales trend for {string}", function(product, context) {
# View the sales trend for the specified product
})
then("they should see the sales trend plot for {string}", function(product, context) {
# Verify the sales trend plot is displayed for the specified product
})
Don't ever miss when Users can no longer interact with your code the way you specified.
Run your scenarios and verify the programmed behaviors are still valid.
Define which source files should be mutated and how.
Plan tests for all files or only for files you're working on. You're in control of the scope of your testing.
Get a score of how often your tests catch mutations (bugs) in your code.
> muttest::muttest(plan)
#> ℹ Mutation Testing
#> | K | S | E | T | % | Mutator | File
#> x | 0 | 1 | 0 | 1 | 0 | + → - | calculate.R
#> ✔ | 1 | 1 | 0 | 2 | 50 | * → / | calculate.R
#> ── Mutation Testing Results ────────────────────────────────────────────────────
#> [ KILLED 1 | SURVIVED 1 | ERRORS 0 | TOTAL 2 | SCORE 50.0% ]
See which source files needs better tests.
Patch the gaps that won't be caught by your tests or code coverage.
# tests/acceptance/test-budget.R
test_that("Scenario: I can inspect my net balance", {
# Given
dsl$record_income(2000)
dsl$record_expense(500)
# When
dsl$inspect_finances()
# Then
dsl$verify_total_income(2000)
dsl$verify_total_expenses(500)
dsl$verify_net_balance(1500)
dsl$teardown()
})
Transform vague requirements into clear, testable user stories that define what users want to accomplish.
Turn user scenarios into working code that validates your application behaves as expected.
Create a testing vocabulary that bridges technical implementation with business language.
Focus on behavior, not implementation details, allowing your UI to evolve without breaking tests.
Learn practical techniques for building more maintainable, testable Shiny applications.
Learn different testing strategies and when to apply them for maximum effectiveness in Shiny apps.
Convert business requirements into automated tests that validate your application meets user needs.
Test each Shiny module independently to ensure they function correctly before integration.
Use dependency injection to replace external services with test doubles for faster, more reliable tests.
Apply a systematic testing methodology that improves code quality and development speed.
Understand the core principles of Behavior-Driven Development and why it improves software quality.
Cooperate with stakeholders to transform vague requirements into clear, testable scenarios.
Master the Given-When-Then syntax to write scenarios that describe system behavior in a structured way.
Execute specifications using an R implementation of Cucumber.
I’m a software engineer specializing in R with 5+ years of experience.
I believe automated testing is the key to building quality software.
My journey into R testing began with a project where to develop code, you had to be connected to the production environment. Turns out, it was a terrible developer experience.
I'm particularly passionate about knowledge sharing, which is why I maintain an active blog and R Tests Gallery. I believe that when we share our testing experiences—both successes and failures—we all become better developers.
I approach testing with a practical mindset: tests should make development faster and more confident, not slower and more burdensome. My goal is to help teams find testing strategies that actually enhance their workflow.