一键导入
tdd-workflow
Test-driven development workflow. Use when writing any R code (writing new features, fixing bugs, refactoring, or reviewing tests).
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Test-driven development workflow. Use when writing any R code (writing new features, fixing bugs, refactoring, or reviewing tests).
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Guide for writing R code. Use when writing new functions, designing APIs, or reviewing/modifying existing R code.
Creates GitHub issues for the package repository. Use when asked to create, file, or open a GitHub issue, or when planning new features or functions that need to be tracked.
| name | tdd-workflow |
| trigger | writing or reviewing tests |
| description | Test-driven development workflow. Use when writing any R code (writing new features, fixing bugs, refactoring, or reviewing tests). |
Write a failing test first, then implement the minimal code to make it pass, then refactor. Never write implementation code without a failing test driving it.
Tests for R/{name}.R go in tests/testthat/test-{name}.R. Place new tests next to similar existing ones.
# Full suite
devtools::test(reporter = "check")
# Single file
devtools::test(filter = "name", reporter = "check")
Testing functions load code automatically. You do not need to call library() or devtools::load_all() separately.
Goal: 100% for every edited file. After editing R/file_name.R, verify:
covr_res <- devtools:::test_coverage_active_file("R/file_name.R")
which(purrr::map_int(covr_res, "value") == 0)
Files excluded from the coverage requirement:
R/*-package.RR/aaa-shared_params.RR/import-standalone-*.RTest individual functions in isolation:
test_that("fetch_records() returns a tibble (#2)", {
result <- fetch_records(sample_input)
expect_s3_class(result, "tbl_df")
})
Test end-to-end pipelines through multiple functions:
test_that("build_report() produces expected output (#15)", {
input <- data.frame(value = c(1.123, 2.456, NA))
result <- build_report(input, tempfile())
expect_equal(nrow(result), 2L)
})
For complex outputs that are hard to specify with equality assertions:
test_that("build_summary print method is stable (#123)", {
expect_snapshot(print(build_summary(sample_data)))
})
When snapshots change intentionally, check the content of the file corresponding to the edited test file, then accept:
testthat::snapshot_accept("test_name")
Snapshots are stored in tests/testthat/_snaps/. The filename corresponds to the R file being tested, ending with .md.
desc of every new test_that() call should end with one or more parenthetical issue references for the issue(s) verified by those tests — typically the issue currently being solved. Never guess or invent issue numbers. Determine the number from the user's prompt, the branch name (git branch --show-current), or gh issue list. Before writing a number, verify you can trace it to one of these sources. If no tracked issue applies, use #noissue. The numbers in the examples below are illustrative placeholders — do not copy them:
test_that("fetch_records() returns correct columns (#1)", { ... })
test_that("build_summary() returns correct columns (#2, #3)", { ... })
test_that(".check_record() errors on empty input (#noissue)", { ... })
# Deprecated → Modern
context("Data validation") # Remove — filename serves this purpose
expect_equivalent(x, y) # expect_equal(x, y, ignore_attr = TRUE)
with_mock(...) # local_mocked_bindings(...)
expect_is(x, "data.frame") # expect_s3_class(x, "data.frame")
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
Errors thrown by this package (via .pkg_abort()) should always be tested
with stbl::expect_pkg_error_snapshot(), which captures both the error class
hierarchy and the user-facing message in one snapshot:
test_that("process_data() errors on empty input (#42)", {
stbl::expect_pkg_error_snapshot(
process_data(data.frame()),
"PlotFTIR",
"empty_input"
)
})
Pass transform = stbl::.transform_path(path) to scrub volatile values (e.g. temp
paths) from the snapshot before comparison.
Errors thrown by stbl (via stbl::to_*() / stbl::stabilize_*())
should be tested with stbl::expect_pkg_error_classes(). Since the message
text is controlled by stbl, only the class hierarchy needs to be asserted:
test_that("process_data() errors on non-integer page_size (#43)", {
stbl::expect_pkg_error_classes(
process_data(sample_data, page_size = "abc"),
"stbl",
"incompatible_type"
)
})
For composite stbl error classes (where the class name contains dashes,
e.g. stbl-error-coerce-character), pass each dash-separated component as a
separate argument. Underscores within a component are kept as-is:
test_that("process_data() errors on non-coercible input (#43)", {
stbl::expect_pkg_error_classes(
process_data(sample_data, value = list(bad = "input")),
"stbl",
"coerce",
"character"
)
})
Errors from other packages can be tested with expect_error(), optionally
wrapped in expect_snapshot() to lock down the message text:
expect_error(code, "pattern")
expect_error(code, class = "some-error-class")
# Lock down both class and message text:
test_that("fetch_records errors on invalid input (#456)", {
expect_snapshot(
(expect_error(
fetch_records("not valid input"),
class = "pkg-error"
))
)
})
expect_warning(code)
expect_no_warning(code)
expect_message(code)
expect_no_message(code)
expect_setequal(x, y) # same elements, any order
expect_in(element, set)
expect_named(x, c("a", "b"))
expect_type(x, "double")
expect_s3_class(x, "tbl_df")
expect_length(x, 10)
expect_null(x)
These expectations are a last resort when more-specific checks aren't available.
expect_true(x)
expect_false(x)
withr patterns for temporary statewithr::local_options(list(PlotFTIR.verbose = TRUE))
withr::local_envvar(MY_VAR = "value")
withr::local_tempfile(lines = c("a", "b"))
Store static test data in tests/testthat/fixtures/ and access via:
test_path("fixtures", "sample.rds")
Mock functions that might hit external servers, etc. by using the vcr package. Mock other unstable functions as needed.