一键导入
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 页面并帮你完成安装。
Document package functions. Use when asked to document functions.
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.
Test-driven development workflow. Use when writing any R code (writing new features, fixing bugs, refactoring, or reviewing tests).
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.
基于 SOC 职业分类
| 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()),
"{{{package}}}",
"empty_input"
)
})
Warnings thrown by this package (via .pkg_warn()) should be tested with
stbl::expect_pkg_warning_snapshot():
test_that("process_data() warns on dropped rows (#42)", {
stbl::expect_pkg_warning_snapshot(
process_data(data.frame(value = c(1, NA))),
"{{{package}}}",
"dropped_rows"
)
})
Messages thrown by this package (via .pkg_inform()) should be tested with
stbl::expect_pkg_message_snapshot():
test_that("process_data() informs on defaults used (#42)", {
stbl::expect_pkg_message_snapshot(
process_data(data.frame(value = 1)),
"{{{package}}}",
"used_defaults"
)
})
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({{{package}}}.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 have unstable output, hit external servers, etc.
local_mocked_bindings(
.other_fn = function(...) "mocked_result"
)
result <- my_function_that_calls_other_fn()