r-bayes
Patterns for Bayesian inference in R using brms, including multilevel models, DAG validation, and marginal effects. Use when performing Bayesian analysis.
Test-driven development workflow for R using testthat. Use when writing new features, fixing bugs, or refactoring code. Enforces test-first development with 80%+ coverage.
$ npx -y skills add ab604/claude-code-r-skills --skill tdd-workflow --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/tdd-workflowContext preview
The summary Claude sees to decide when to auto-load this skill.
Test-driven development workflow for R using testthat. Use when writing new features, fixing bugs, or refactoring code. Enforces test-first development with 80%+ coverage.
name: tdd-workflow description: Test-driven development workflow for R using testthat. Use when writing new features, fixing bugs, or refactoring code. Enforces test-first development with 80%+ coverage.
This skill ensures all R code development follows TDD principles with comprehensive test coverage using testthat.
Initialize testing infrastructure for your package:
# Set up testthat (Edition 3)
usethis::use_testthat(3)
# Create a test file for an existing source file
usethis::use_test("function_name")
# Or create test and source file together
usethis::use_r("function_name")
usethis::use_test("function_name")ALWAYS write tests first, then implement code to make tests pass.
Tests follow a three-level hierarchy: **File → Test → Expectation**
Individual functions and utilities:
test_that("rescale01 normalizes to [0, 1] range", {
expect_equal(rescale01(c(0, 5, 10)), c(0, 0.5, 1))
expect_equal(rescale01(c(-10, 0, 10)), c(0, 0.5, 1))
})
test_that("rescale01 handles edge cases", {
expect_equal(rescale01(c(5, 5, 5)), c(NaN, NaN, NaN))
expect_equal(rescale01(numeric(0)), numeric(0))
expect_equal(rescale01(c(0, NA, 10)), c(0, NA, 1))
})Function interactions and workflows:
test_that("data pipeline produces expected output", {
raw_data <- read_fixture("sample_input.csv")
result <- raw_data |>
clean_data() |>
transform_features() |>
summarize_results()
expect_s3_class(result, "tbl_df")
expect_named(result, c("group", "mean", "sd", "n"))
expect_true(all(result$n > 0))
})For complex outputs that are hard to specify:
test_that("model summary format is stable", {
model <- fit_model(test_data)
expect_snapshot(print(summary(model)))
})
test_that("error messages are informative", {
expect_snapshot(
validate_input(invalid_data),
error = TRUE
)
})**Snapshot workflow:**
# Review snapshot changes
testthat::snapshot_review("test_name")
# Accept snapshot changes
testthat::snapshot_accept("test_name")Snapshots are stored in `tests/testthat/_snaps/` directory.
For behavior-driven development, use `describe()` and `it()`:
describe("matrix()", {
it("can be multiplied by a scalar", {
m1 <- matrix(1:4, 2, 2)
m2 <- m1 * 2
expect_equal(matrix(c(2, 4, 6, 8), 2, 2), m2)
})
it("can be transposed", {
m <- matrix(1:4, 2, 2)
expect_equal(t(m), matrix(c(1, 3, 2, 4), 2, 2))
})
})**Key distinction:** "describe() verifies you implement the right things, test_that() ensures you do things right."
Each test should contain all setup, execution, and teardown code. Tests must be independent and runnable in isolation without relying on ambient state or prior test execution.
# GOOD: Self-contained
test_that("function works with specific data", {
data <- tibble(x = 1:10, y = rnorm(10)) # Setup
result <- my_function(data) # Execute
expect_equal(nrow(result), 10) # Assert
})
# BAD: Depends on external state
# setup_data <- tibble(...) # Created outside test
test_that("function works", {
result <- my_function(setup_data) # Relies on external data
expect_equal(nrow(result), 10)
})Repetition is acceptable in tests—duplicate setup code rather than extracting it elsewhere. Clarity outweighs avoiding duplication.
# GOOD: Duplicated but clear
test_that("clean_data handles missing values", {
data <- tibble(x = c(1, NA, 3), y = c(4, 5, 6))
result <- clean_data(data)
expect_equal(nrow(result), 2)
})
test_that("clean_data handles invalid values", {
data <- tibble(x = c(1, -999, 3), y = c(4, 5, 6))
result <- clean_data(data, invalid = -999)
expect_equal(nrow(result), 2)
})
# ACCEPTABLE: Each test is self-contained and readableWrite tests assuming they'll fail and require debugging. Make logic explicit and obvious. Run tests in fresh R sessions independently.
During development, prefer `devtools::load_all()` over `library()`. This:
Edition 3 provides improved snapshot testing, better diffs via waldo, unified condition handling, parallel execution support, and byte-compiled code compatibility for mocking.
# DEPRECATED: context() calls
context("Data validation") # Remove - filename serves this purpose
# DEPRECATED: expect_equivalent()
expect_equivalent(x, y)
# MODERN:
expect_equal(x, y, ignore_attr = TRUE)
# DEPRECATED: with_mock()
with_mock(external_call = function() "mocked", {
result <- my_function()
})
# MODERN:
local_mocked_bindings(
external_call = function() "mocked"
)
result <- my_function()
# DEPRECATED: expect_is()
expect_is(x, "data.frame")
# MODERN:
expect_s3_class(x, "data.frame")In `DESCRIPTION`, ensure:
Config/testthat/edition: 3
Or initialize with:
usethis::use_testthat(3)
expect_equal(x, y) # With numeric tolerance expect_equal(x, y, tolerance = 0.001) expect
A curated collection of Claude Code configurations for modern R use. These skills, rules, commands, and agents help Claude Code understand R best practices and generate idiomatic, high-quality R code.
Repo: ab604/claude-code-r-skills
Patterns for Bayesian inference in R using brms, including multilevel models, DAG validation, and marginal effects. Use when performing Bayesian analysis.
R object-oriented programming guide for S7, S3, S4, and vctrs. Use when designing R classes or choosing an OOP system.
R package development guide covering dependencies, API design, testing, and documentation. Use when developing R packages.
R performance best practices including profiling, benchmarking, vctrs, and optimization strategies. Use when optimizing R code.
R style guide covering naming conventions, spacing, layout, and function design best practices. Use when writing R code.
rlang metaprogramming patterns for data-masking, injection operators, and dynamic dots. Use when writing functions that use tidy evaluation.