r-testing
R testing patterns: testthat 3e with expect_* assertions, snapshot testing, mocking with mockery and httptest2, covr code coverage, lintr static analysis, property-based testing with hedgehog, testing Shiny apps with shinytest2. Use when writing or reviewing R tests.
Best use case
r-testing is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
R testing patterns: testthat 3e with expect_* assertions, snapshot testing, mocking with mockery and httptest2, covr code coverage, lintr static analysis, property-based testing with hedgehog, testing Shiny apps with shinytest2. Use when writing or reviewing R tests.
Teams using r-testing should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/r-testing/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How r-testing Compares
| Feature / Agent | r-testing | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
R testing patterns: testthat 3e with expect_* assertions, snapshot testing, mocking with mockery and httptest2, covr code coverage, lintr static analysis, property-based testing with hedgehog, testing Shiny apps with shinytest2. Use when writing or reviewing R tests.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
Related Guides
SKILL.md Source
# R Testing
## When to Activate
- Writing tests with testthat in R packages
- Mocking HTTP calls or functions in tests
- Setting up coverage reporting with covr
- Testing Shiny applications with shinytest2
- Choosing between `expect_equal` and `expect_identical` for numeric vs. exact comparison
- Using snapshot testing to lock in the printed output of S3 objects or complex data structures
- Enforcing a minimum coverage percentage in CI with `covr::percent_coverage`
- Running property-based tests with `hedgehog` to verify algebraic laws like commutativity or idempotence
---
## testthat 3e — Modern Syntax
```r
# tests/testthat/test-compute.R
library(testthat)
test_that("compute_mean returns correct trimmed mean", {
expect_equal(compute_mean(c(1, 2, 3, 4, 5)), 3)
expect_equal(compute_mean(c(1, 2, 3, 100), trim = 0.25), 2.5)
})
test_that("compute_mean removes NA by default", {
result <- compute_mean(c(1, NA, 3))
expect_equal(result, 2)
})
test_that("compute_mean errors on non-numeric input", {
expect_error(
compute_mean(c("a", "b")),
regexp = "must be numeric"
)
})
test_that("compute_mean returns NaN for empty vector", {
expect_true(is.nan(compute_mean(numeric(0))))
})
```
### Assertion Reference
```r
# Equality
expect_equal(actual, expected) # numeric tolerance applied
expect_identical(actual, expected) # exact, no tolerance
expect_equivalent(actual, expected) # ignores attributes
# Type checks
expect_type(x, "double")
expect_s3_class(df, "data.frame")
expect_s4_class(m, "Matrix")
expect_inherits(x, "tbl_df")
# Conditions
expect_error(expr, regexp = NULL) # regexp: optional pattern
expect_warning(expr, regexp = NULL)
expect_message(expr, regexp = NULL)
expect_no_error(expr)
expect_no_warning(expr)
# Logical
expect_true(cond)
expect_false(cond)
expect_null(x)
expect_length(x, n)
# Data frames
expect_equal(nrow(df), 5L)
expect_named(df, c("id", "name", "value"))
expect_contains(names(df), "created_at")
# Snapshots
expect_snapshot(print(my_object)) # console output snapshot
expect_snapshot_file(path, "chart.png") # file snapshot
```
---
## Snapshot Testing
Snapshot tests capture output and fail if it changes unexpectedly.
```r
test_that("user_summary prints correctly", {
user <- new_user(id = 1L, name = "Alice", email = "alice@example.com")
expect_snapshot(print(user))
})
# Update snapshots after intentional change:
# testthat::snapshot_review()
# testthat::snapshot_accept()
```
---
## Mocking with mockery
```r
library(mockery)
test_that("fetch_data calls correct URL", {
mock_response <- list(
status_code = 200L,
content = list(id = 1L, name = "Alice")
)
stub(fetch_user, "httr::GET", mock(mock_response))
result <- fetch_user(id = 1L)
expect_equal(result$name, "Alice")
})
test_that("fetch_data handles 404", {
stub(fetch_user, "httr::GET", mock(list(status_code = 404L)))
expect_error(fetch_user(id = 999L), "not found")
})
```
---
## Mocking HTTP with httptest2
```r
library(httptest2)
test_that("GET /users/1 returns user data", {
with_mock_api({
result <- get_user(1L)
expect_equal(result$name, "Alice")
})
})
# Record real API responses for replay:
# httptest2::capture_requests({ get_user(1L) })
# Saves to tests/testthat/api.example.com/users/1.json
```
---
## Code Coverage with covr
```r
# Run package coverage
cov <- covr::package_coverage()
# Print summary
covr::zero_coverage(cov) # show uncovered lines
print(cov)
# HTML report
covr::report(cov)
# Enforce minimum in CI
min_coverage <- 80
pct <- covr::percent_coverage(cov)
if (pct < min_coverage) {
stop(sprintf("Coverage %.1f%% below minimum %.0f%%", pct, min_coverage))
}
```
---
## Shiny App Testing with shinytest2
```r
library(shinytest2)
test_that("user input triggers correct output", {
app <- AppDriver$new(app_dir = ".", name = "my_app")
app$set_inputs(user_id = 1)
app$click("btn_fetch")
app$wait_for_idle()
output <- app$get_value(output = "user_name")
expect_equal(output, "Alice")
app$stop()
})
```
---
## Property-Based Testing with hedgehog
```r
library(hedgehog)
test_that("sum is commutative (property)", {
forall(
list(gen.int(100), gen.int(100)),
function(a, b) expect_equal(a + b, b + a)
)
})
test_that("sort is idempotent (property)", {
forall(
gen.element(list(gen.c(gen.double()), gen.c(gen.int(50)))),
function(x) expect_equal(sort(sort(x)), sort(x))
)
})
```
---
## Test File Organization
```
my_package/
R/
compute.R
fetch.R
shiny_app.R
tests/
testthat/
test-compute.R
test-fetch.R
test-shiny.R
fixtures/
user_1.json
_snaps/
user_summary.md
testthat.R
DESCRIPTION
```
---
## Running Tests
```r
# All tests
devtools::test()
# Single file
testthat::test_file("tests/testthat/test-compute.R")
# Specific test by pattern
devtools::test(filter = "compute")
# With coverage
covr::package_coverage()
```Related Skills
visual-testing
Visual Regression Testing: tool comparison (Chromatic/Percy/Playwright screenshots/BackstopJS), pixel-diff vs AI-based comparison, baseline management, flakiness strategies (masks, tolerances, waitForLoadState), CI integration with GitHub Actions, and Storybook integration.
typescript-testing
TypeScript testing patterns: Vitest for unit/integration, Playwright for E2E, MSW for API mocking, Testing Library for React components. Core TDD methodology for TypeScript/JavaScript projects.
swift-testing
Swift testing patterns: Swift Testing framework (Swift 6+), XCTest for UI tests, async/await test cases, actor testing, Combine testing, and XCUITest for UI automation. TDD for Swift/SwiftUI.
swift-protocol-di-testing
Protocol-based dependency injection for testable Swift code — mock file system, network, and external APIs using focused protocols and Swift Testing.
scala-testing
Scala testing with ScalaTest, MUnit, and ScalaCheck: FunSpec/FlatSpec test structure, property-based testing with forAll, mocking with MockitoSugar, Cats Effect testing with munit-cats-effect (runTest/IOSuite), ZIO Test, Testcontainers-Scala for database integration tests, and CI integration with sbt. Use when writing or reviewing Scala tests.
rust-testing
Rust testing patterns — unit tests with mockall, integration tests with sqlx transactions, HTTP handler testing (axum), benchmarks (criterion), property tests (proptest), fuzzing, and CI with cargo-nextest.
rust-testing-advanced
Advanced Rust testing anti-patterns and corrections — cfg(test) placement, expect() over unwrap(), mockall expectation ordering, executor mixing (#[tokio::test] vs block_on), PgPool isolation with
ruby-testing
RSpec testing patterns for Ruby and Rails — factories, mocks, request specs, feature specs, VCR, and SimpleCov coverage.
python-testing
Python testing strategies using pytest, TDD methodology, fixtures, mocking, and parametrization. Core testing fundamentals.
python-testing-advanced
Advanced Python testing — async testing with pytest-asyncio, exception/side-effect testing, test organization, common patterns (API, database, class methods), pytest configuration, and CLI reference. Extends python-testing.
php-testing
PHP testing patterns: PHPUnit 11 with mocks and data providers, Pest v3 with expectations and datasets, Laravel feature/HTTP tests with RefreshDatabase, Symfony WebTestCase, PHPStan static analysis, Infection mutation testing. Use when writing or reviewing PHP tests.
load-testing
Load and performance testing with k6 (TypeScript/Go/any HTTP) and Locust (Python). Covers test types (smoke, load, stress, spike, soak), SLO thresholds, CI integration, and interpreting results.