TDD
fossasia/eventyay-interpretation
Test-driven development. An agent skill from fossasia/eventyay-interpretation.
Test-driven development workflow for R using testthat. An agent skill from ab604/claude-code-r-skills.
$ npx skills add ab604/claude-code-r-skills --skill tdd-workflow -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install ab604/claude-code-r-skills tdd-workflow --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/ab604/claude-code-r-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/tdd-workflow .claude/skills/tdd-workflow && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "tdd-workflow" agent skill from https://github.com/ab604/claude-code-r-skills/tree/main/.claude/skills/tdd-workflow into .claude/skills/tdd-workflow/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "tdd-workflow", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/ab604/claude-code-r-skills/tree/main/.claude/skills/tdd-workflowType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add ab604/claude-code-r-skills --skill tdd-workflow -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install ab604/claude-code-r-skills tdd-workflow --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ab604/claude-code-r-skills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/tdd-workflow .agents/skills/tdd-workflow && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "tdd-workflow" agent skill from https://github.com/ab604/claude-code-r-skills/tree/main/.claude/skills/tdd-workflow into .agents/skills/tdd-workflow/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "tdd-workflow", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ab604/claude-code-r-skills --skill tdd-workflow -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install ab604/claude-code-r-skills tdd-workflow --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ab604/claude-code-r-skills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/tdd-workflow .cursor/skills/tdd-workflow && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "tdd-workflow" agent skill from https://github.com/ab604/claude-code-r-skills/tree/main/.claude/skills/tdd-workflow into .cursor/skills/tdd-workflow/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "tdd-workflow", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/ab604/claude-code-r-skills.git --path .claude/skills/tdd-workflow--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add ab604/claude-code-r-skills --skill tdd-workflow -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install ab604/claude-code-r-skills tdd-workflow --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ab604/claude-code-r-skills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/tdd-workflow .gemini/skills/tdd-workflow && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "tdd-workflow" agent skill from https://github.com/ab604/claude-code-r-skills/tree/main/.claude/skills/tdd-workflow into .gemini/skills/tdd-workflow/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "tdd-workflow", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install ab604/claude-code-r-skills tdd-workflowInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add ab604/claude-code-r-skills --skill tdd-workflow -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/ab604/claude-code-r-skills.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/tdd-workflow .github/skills/tdd-workflow && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "tdd-workflow" agent skill from https://github.com/ab604/claude-code-r-skills/tree/main/.claude/skills/tdd-workflow into .github/skills/tdd-workflow/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "tdd-workflow", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ab604/claude-code-r-skills --skill tdd-workflow -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install ab604/claude-code-r-skills tdd-workflow --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ab604/claude-code-r-skills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/tdd-workflow .opencode/skills/tdd-workflow && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "tdd-workflow" agent skill from https://github.com/ab604/claude-code-r-skills/tree/main/.claude/skills/tdd-workflow into .opencode/skills/tdd-workflow/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "tdd-workflow", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
tdd-workflowTest-driven development workflow for R using testthat. An agent skill from ab604/claude-code-r-skills.
TDD Workflow is an agent skill from ab604/claude-code-r-skills. 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.
Its SKILL.md is about 4.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Testing & QA, covering Test-driven development. The repository describes itself as: Claude Code configurations for R development. The licence is MIT.
12 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 529de4f. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are r).
From the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
TDD Workflow loads about 4.8k tokens when it runs. Until then it costs about 46 tokens; SKILL.md has 647 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from ab604/claude-code-r-skills at commit 529de4f, republished under its MIT licence (© ab604). 647 words, ~4,827 tokens.
.claude/skills/tdd-workflow/SKILL.md (or your agent's skills folder).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:
library() calls in testsEdition 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: 3Or initialize with:
usethis::use_testthat(3)expect_equal(x, y) # With numeric tolerance
expect_equal(x, y, tolerance = 0.001)
expect_equal(x, y, ignore_attr = TRUE)
expect_identical(x, y) # Exact match required
expect_all_equal(x) # Every element equal (v3.3.0+)expect_error(code)
expect_error(code, "pattern")
expect_error(code, class = "validation_error")
expect_warning(code)
expect_no_warning(code)
expect_message(code)
expect_no_message(code)expect_setequal(x, y) # Same elements, any order
expect_contains(set, element) # Subset relationship (v3.2.0+)
expect_in(element, set) # Membership check (v3.2.0+)
expect_disjoint(set1, set2) # No overlap (v3.3.0+)
expect_named(x, c("a", "b")) # Named vector/listexpect_type(x, "double")
expect_s3_class(x, "data.frame")
expect_s4_class(x, "S4Class")
expect_r6_class(x, "R6Class")
expect_shape(matrix, c(2, 3)) # Matrix/array dimensions (v3.3.0+)
expect_length(x, 10)expect_true(x)
expect_false(x)
expect_all_true(x) # Every element TRUE (v3.3.0+)
expect_all_false(x) # Every element FALSE (v3.3.0+)expect_null(x)
expect_invisible(result)
expect_output(print(x), "pattern")
expect_snapshot(complex_output)Tests mirror your package structure:
tests/
├── testthat/
│ ├── test-validation.R # Tests for R/validation.R
│ ├── test-processing.R # Tests for R/processing.R
│ ├── test-models.R # Tests for R/models.R
│ ├── test-output.R # Tests for R/output.R
│ ├── helper-fixtures.R # Shared functions (sourced before tests)
│ ├── setup-database.R # Setup code (runs during R CMD check)
│ ├── helper-expectations.R # Custom expectations
│ └── fixtures/ # Static test data files
│ ├── sample_input.csv
│ └── expected_output.rds
└── testthat.R # Test runnertest-*.R - Actual test files (paired with source files)helper-*.R - Shared utility functions, sourced before tests runsetup-*.R - Setup code that runs only during R CMD checkfixtures/ - Static test data, accessed via test_path("fixtures/file")Access fixtures:
test_path("fixtures", "sample_data.csv")Document what the function should do:
# Function: calculate_ci
# Purpose: Calculate bootstrap confidence intervals
# Inputs:
# - data: numeric vector
# - conf_level: confidence level (default 0.95)
# - n_boot: number of bootstrap samples (default 1000)
# Outputs:
# - Named numeric vector with lower and upper bounds
# Edge cases:
# - Handle NA values
# - Error on non-numeric input
# - Error on empty input# tests/testthat/test-calculate_ci.R
library(testthat)
test_that("calculate_ci returns correct structure", {
set.seed(123)
result <- calculate_ci(1:100)
expect_type(result, "double")
expect_named(result, c("lower", "upper"))
expect_true(result["lower"] < result["upper"])
})
test_that("calculate_ci respects confidence level", {
set.seed(123)
ci_95 <- calculate_ci(1:100, conf_level = 0.95)
ci_99 <- calculate_ci(1:100, conf_level = 0.99)
# 99% CI should be wider
expect_true(ci_99["upper"] - ci_99["lower"] > ci_95["upper"] - ci_95["lower"])
})
test_that("calculate_ci handles NA values", {
set.seed(123)
result <- calculate_ci(c(1:100, NA, NA))
expect_false(any(is.na(result)))
})
test_that("calculate_ci validates inputs", {
expect_error(calculate_ci("not numeric"), class = "validation_error")
expect_error(calculate_ci(numeric(0)), class = "validation_error")
expect_error(calculate_ci(1:10, conf_level = 1.5), class = "validation_error")
})devtools::test()
# ✖ calculate_ci returns correct structure
# ✖ calculate_ci respects confidence level
# ✖ calculate_ci handles NA values
# ✖ calculate_ci validates inputs# R/calculate_ci.R
#' Calculate Bootstrap Confidence Interval
#'
#' @param x Numeric vector
#' @param conf_level Confidence level (default 0.95)
#' @param n_boot Number of bootstrap samples (default 1000)
#' @return Named numeric vector with lower and upper bounds
#' @export
calculate_ci <- function(x, conf_level = 0.95, n_boot = 1000) {
# Validate inputs
if (!is.numeric(x)) {
cli::cli_abort("{.arg x} must be numeric", class = "validation_error")
}
if (length(x) == 0) {
cli::cli_abort("{.arg x} cannot be empty", class = "validation_error")
}
if (conf_level <= 0 || conf_level >= 1) {
cli::cli_abort("{.arg conf_level} must be between 0 and 1", class = "validation_error")
}
# Remove NA values
x <- x[!is.na(x)]
# Bootstrap
boot_means <- replicate(n_boot, mean(sample(x, replace = TRUE)))
# Calculate quantiles
alpha <- 1 - conf_level
c(
lower = unname(quantile(boot_means, alpha / 2)),
upper = unname(quantile(boot_means, 1 - alpha / 2))
)
}devtools::test()
# ✔ calculate_ci returns correct structure
# ✔ calculate_ci respects confidence level
# ✔ calculate_ci handles NA values
# ✔ calculate_ci validates inputsImprove while keeping tests green:
# Extract validation to helper
validate_ci_inputs <- function(x, conf_level) {
if (!is.numeric(x)) {
cli::cli_abort("{.arg x} must be numeric", class = "validation_error")
}
if (length(x) == 0) {
cli::cli_abort("{.arg x} cannot be empty", class = "validation_error")
}
if (conf_level <= 0 || conf_level >= 1) {
cli::cli_abort("{.arg conf_level} must be between 0 and 1", class = "validation_error")
}
}
calculate_ci <- function(x, conf_level = 0.95, n_boot = 1000) {
validate_ci_inputs(x, conf_level)
x <- x[!is.na(x)]
boot_means <- replicate(n_boot, mean(sample(x, replace = TRUE)))
alpha <- 1 - conf_level
c(
lower = unname(quantile(boot_means, alpha / 2)),
upper = unname(quantile(boot_means, 1 - alpha / 2))
)
}covr::package_coverage()
# calculate_ci.R: 100%test_that("clean_data removes invalid rows", {
input <- tibble(
id = 1:4,
value = c(1, NA, 3, -999)
)
result <- clean_data(input, invalid_value = -999)
expect_equal(nrow(result), 2)
expect_equal(result$id, c(1, 3))
expect_false(anyNA(result$value))
})test_that("weighted_mean matches manual calculation", {
x <- c(1, 2, 3)
w <- c(1, 2, 1)
result <- weighted_mean(x, w)
expected <- sum(x * w) / sum(w) # (1 + 4 + 3) / 4 = 2
expect_equal(result, expected)
})# helper-fixtures.R
read_fixture <- function(name) {
path <- testthat::test_path("fixtures", name)
readr::read_csv(path, show_col_types = FALSE)
}
# test-pipeline.R
test_that("pipeline handles real data", {
input <- read_fixture("sample_data.csv")
result <- process_pipeline(input)
expect_snapshot(result)
})test_that("fetch_data handles API errors", {
# Mock the API call
local_mocked_bindings(
httr2_request = function(...) {
stop("API unavailable")
}
)
expect_error(
fetch_data("endpoint"),
"API unavailable"
)
})Use withr functions to manage temporary state with automatic restoration:
test_that("function respects options", {
# Temporarily set options
withr::local_options(list(digits = 2))
result <- format_number(3.14159)
expect_equal(result, "3.14")
})
test_that("function writes to temp file", {
# Create temp file that's automatically cleaned up
tmp <- withr::local_tempfile(lines = c("line 1", "line 2"))
result <- process_file(tmp)
expect_equal(result$n_lines, 2)
})
test_that("function uses custom environment variable", {
# Temporarily set env var
withr::local_envvar(MY_VAR = "test_value")
result <- get_config()
expect_equal(result$my_var, "test_value")
})Choose the appropriate approach for your testing needs:
Create data on-demand with helper functions:
# helper-data.R
make_sample_data <- function(n = 100) {
tibble(
id = 1:n,
group = sample(c("A", "B"), n, replace = TRUE),
value = rnorm(n)
)
}
# test-analysis.R
test_that("analysis handles grouped data", {
data <- make_sample_data(n = 50)
result <- analyze_groups(data)
expect_s3_class(result, "tbl_df")
})Handle side effects using withr:
test_that("function reads CSV correctly", {
# Create temp file with cleanup
tmp <- withr::local_tempfile(fileext = ".csv")
write.csv(mtcars, tmp, row.names = FALSE)
result <- read_and_process(tmp)
expect_equal(nrow(result), 32)
})Store data files in fixtures/ directory:
# Store in: tests/testthat/fixtures/sample_data.csv
test_that("function handles real data format", {
path <- test_path("fixtures", "sample_data.csv")
data <- read_csv(path)
result <- process_data(data)
expect_true(all(result$valid))
})# Don't test internal state
expect_equal(obj$internal_cache, expected_cache)# Test observable behavior
expect_equal(get_result(obj), expected_result)# Breaks on any output change
expect_equal(as.character(result), "Mean: 5.234567890")# Robust to formatting changes
expect_equal(result$mean, 5.23, tolerance = 0.01)test_that("creates data", { global_data <<- create() })
test_that("uses data", { process(global_data) }) # Depends on previous!test_that("creates and uses data", {
data <- create()
result <- process(data)
expect_true(is_valid(result))
})# When a test fails, don't change the test (unless it's wrong)
test_that("function returns 42", {
expect_equal(my_function(), 42) # Test fails
})
# DON'T DO THIS:
test_that("function returns 41", {
expect_equal(my_function(), 41) # Changed to pass - WRONG!
})# Fix the code to match expected behavior
test_that("function returns 42", {
expect_equal(my_function(), 42) # Test fails
})
# Fix my_function() implementation instead# Review and accept snapshot changes
testthat::snapshot_review("test_name")
testthat::snapshot_accept("test_name")# Run coverage report
covr::package_coverage()
# Interactive HTML report
covr::report()
# Check specific thresholds
cov <- covr::package_coverage()
pct <- covr::percent_coverage(cov)
if (pct < 80) {
stop("Coverage below 80%: ", round(pct, 1), "%")
}
# In testthat.R or as a coverage check
covr::package_coverage(
type = "all",
line_coverage = 0.80,
function_coverage = 0.80
)# Micro: Interactive development
devtools::load_all()
expect_equal(my_function(1), 1) # Direct expectation
# Mezzo: Single file
testthat::test_file("tests/testthat/test-validation.R")
# RStudio: Ctrl/Cmd+Shift+T
# Macro: Full suite
devtools::test()
devtools::check() # Full package validation# Find slow tests
devtools::test(reporter = "slow")
# Progress reporter (verbose)
devtools::test(reporter = "progress")
# Test execution order independence
devtools::test(shuffle = TRUE)# Watch mode - auto-run on file changes
testthat::auto_test_package()Edition 3 supports parallel test execution for faster runs on multi-core systems.
# All tests
devtools::test()
# All tests (keyboard shortcut)
# RStudio: Ctrl/Cmd+Shift+T
# With coverage
covr::package_coverage()
# Specific file
testthat::test_file("tests/testthat/test-validation.R")
# Watch mode
testthat::auto_test_package()
# Verbose output
devtools::test(reporter = "progress")
# Find slow tests
devtools::test(reporter = "slow")
# Test independence
devtools::test(shuffle = TRUE)
# Full package check
devtools::check()Remember: Tests are not optional. They are the safety net that enables confident refactoring, rapid development, and production reliability. Write them FIRST.
© ab604, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .claude/skills/tdd-workflow of ab604/claude-code-r-skills.
Open the folder on GitHubat commit 529de4f
We found 2 copies of this SKILL.md (exact, near-identical or edited) in other folders, from 2 other GitHub owners. This page covers the copy in ab604/claude-code-r-skills, which our catalogue first saw on October 7, 2026.
TDD Workflow next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| TDD Workflow this skillab604/claude-code-r-skills | 206 | 2 repos | ~4.8k | Automated safety check: Pass | MIT | |
| TDDfossasia/eventyay-interpretation | 1.6k | 28 repos | ~1.1k | Automated safety check: Pass | Apache-2.0 | |
| TDD WorkflowhellangleZ/burn-in-cceverywhere-ralph | 112 | 11 repos | ~2.4k | Automated safety check: Pass | None | |
| TDDsanity-io/sanity | 6.4k | 20 repos | ~1k | Automated safety check: Pass | MIT | |
| Test Driven Developmentfarm-fe/farm | 5.6k | 49 repos | ~2.5k | Automated safety check: Pass | MIT | |
| Tapd Story PipelineTencentBlueKing/bk-bcs | 840 | — | ~2.6k | Automated safety check: Pass | Custom licence |
fossasia/eventyay-interpretation
Test-driven development. An agent skill from fossasia/eventyay-interpretation.
hellangleZ/burn-in-cceverywhere-ralph
A skill your agent uses when writing new features, fixing bugs, or refactoring code.
sanity-io/sanity
Test-driven development with red-green-refactor loop. An agent skill from sanity-io/sanity.
farm-fe/farm
A skill your agent uses when implementing any feature or bugfix, before writing implementation code
TencentBlueKing/bk-bcs
单需求实现流水线——把一个 TAPD 需求从零推进到代码提交。自动串联技术澄清、 开发计划、任务拆分、TDD 实现、架构/安全校验、代码提交六个阶段。
maddhruv/absolute
One-time setup for absolute: interview how you want it to behave (output style, autonomy, TDD strictness, spec dir, families) + detect the stack once, then write .absolute.config.json (project…
ab604/claude-code-r-skills
Patterns for Bayesian inference in R using brms, including multilevel models, DAG validation, and marginal effects.
ab604/claude-code-r-skills
R object-oriented programming guide for S7, S3, S4, and vctrs.
ab604/claude-code-r-skills
R package development guide covering dependencies, API design, testing, and documentation.
ab604/claude-code-r-skills
R performance best practices including profiling, benchmarking, vctrs, and optimization strategies.
ab604/claude-code-r-skills
R style guide covering naming conventions, spacing, layout, and function design best practices.
ab604/claude-code-r-skills
rlang metaprogramming patterns for data-masking, injection operators, and dynamic dots.
Categories
Test-driven development workflow for R using testthat. An agent skill from ab604/claude-code-r-skills. TDD Workflow is an agent skill from ab604/claude-code-r-skills. Test-driven development workflow for R using testthat.
TDD Workflow fits situations like: writing new features; refactoring code.
Run `npx skills add ab604/claude-code-r-skills --skill tdd-workflow -a claude-code`. Or copy the skill folder (.claude/skills/tdd-workflow in ab604/claude-code-r-skills) into .claude/skills/tdd-workflow in your project. Claude Code loads it when a task matches its description.
Run `npx skills add ab604/claude-code-r-skills --skill tdd-workflow -a codex`. Or copy the skill folder (.claude/skills/tdd-workflow in ab604/claude-code-r-skills) into .agents/skills/tdd-workflow in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add ab604/claude-code-r-skills --skill tdd-workflow -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/tdd-workflow, .gemini/skills/tdd-workflow, .github/skills/tdd-workflow and .opencode/skills/tdd-workflow in your project.
SKILL.md names no scripts, command-line tools or credentials: TDD Workflow is instructions for the agent only.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
TDD Workflow is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 4.8k tokens (SKILL.md is roughly 19k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with TDD Workflow: TDD (fossasia/eventyay-interpretation, 1.6k stars), TDD Workflow (hellangleZ/burn-in-cceverywhere-ralph, 112 stars), TDD (sanity-io/sanity, 6.4k stars) and Test Driven Development (farm-fe/farm, 5.6k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
ab604 (a GitHub user) maintains it in ab604/claude-code-r-skills, which has 206 GitHub stars. The repository holds 8 skills in this directory. The repository was last updated on September 17, 2026.
Source: ab604/claude-code-r-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.