write-testthat-tests
정보
이 Claude Skill은 R 패키지 함수를 위한 포괄적인 testthat(에디션 3) 유닛 테스트를 생성합니다. 개발자가 새로운 함수에 대한 테스트를 추가하고, 기존 코드의 커버리지를 높이며, 테스트 인프라를 설정하는 데 도움을 줍니다. 본 스킬은 테스트 구성, 예상 결과 검증, 모의 테스트, 스냅샷 테스트, 매개변수화된 테스트를 다룹니다.
빠른 설치
Claude Code
추천npx skills add pjt222/agent-almanac -a claude-code/plugin add https://github.com/pjt222/agent-almanacgit clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/write-testthat-testsClaude Code에서 이 명령을 복사하여 붙여넣어 스킬을 설치하세요
문서
Write testthat Tests
Create comprehensive tests for R package functions using testthat edition 3.
When to Use
- Adding tests for new package functions
- Increasing test coverage for existing code
- Writing regression tests for bug fixes
- Setting up test infrastructure for a new package
Inputs
- Required: R functions to test
- Required: Expected behavior and edge cases
- Optional: Test fixtures or sample data
- Optional: Target coverage percentage (default: 80%)
Procedure
Step 1: Set Up Test Infrastructure
If not already done:
usethis::use_testthat(edition = 3)
This creates tests/testthat.R and tests/testthat/ directory.
Got: tests/testthat.R and tests/testthat/ directory created. DESCRIPTION has Config/testthat/edition: 3 set.
If fail: If usethis is not available, manually create tests/testthat.R containing library(testthat); library(packagename); test_check("packagename") and add tests/testthat/ directory.
Step 2: Create Test File
usethis::use_test("function_name")
This creates tests/testthat/test-function_name.R with a template.
Got: Test file created at tests/testthat/test-function_name.R with a placeholder test_that() block ready to fill in.
If fail: If usethis::use_test() is not available, manually create the file. Follow the naming convention test-<function_name>.R.
Step 3: Write Basic Tests
test_that("weighted_mean computes correct result", {
expect_equal(weighted_mean(1:3, c(1, 1, 1)), 2)
expect_equal(weighted_mean(c(10, 20), c(1, 3)), 17.5)
})
test_that("weighted_mean handles NA values", {
expect_equal(weighted_mean(c(1, NA, 3), c(1, 1, 1), na.rm = TRUE), 2)
expect_true(is.na(weighted_mean(c(1, NA, 3), c(1, 1, 1), na.rm = FALSE)))
})
test_that("weighted_mean validates input", {
expect_error(weighted_mean("a", 1), "numeric")
expect_error(weighted_mean(1:3, 1:2), "length")
})
Got: Basic tests cover correct output for typical inputs, NA handling behavior, and input validation error messages.
If fail: If tests fail immediately, verify the function is loaded (devtools::load_all()). If error messages do not match, use a regex pattern in expect_error() instead of an exact string.
Step 4: Test Edge Cases
test_that("weighted_mean handles edge cases", {
# Empty input
expect_error(weighted_mean(numeric(0), numeric(0)))
# Single value
expect_equal(weighted_mean(5, 1), 5)
# Zero weights
expect_true(is.nan(weighted_mean(1:3, c(0, 0, 0))))
# Very large values
expect_equal(weighted_mean(c(1e15, 1e15), c(1, 1)), 1e15)
# Negative weights
expect_error(weighted_mean(1:3, c(-1, 1, 1)))
})
Got: Edge cases are covered: empty input, single values, zero weights, extreme values, and invalid inputs. Each edge case has a clear expected behavior.
If fail: If the function does not handle an edge case as expected, decide whether to fix the function or adjust the test. Document the intended behavior for ambiguous cases.
Step 5: Use Fixtures for Complex Tests
Create tests/testthat/fixtures/ for test data:
# tests/testthat/helper.R (loaded automatically)
create_test_data <- function() {
data.frame(
x = c(1, 2, 3, NA, 5),
group = c("a", "a", "b", "b", "b")
)
}
# In test file
test_that("process_data works with grouped data", {
test_data <- create_test_data()
result <- process_data(test_data)
expect_s3_class(result, "data.frame")
expect_equal(nrow(result), 2)
})
Got: Fixtures provide consistent test data across multiple test files. Helper functions in tests/testthat/helper.R are loaded automatically by testthat.
If fail: If helper functions are not found, ensure the file is named helper.R (not helpers.R) and is located in tests/testthat/. Restart the R session if needed.
Step 6: Mock External Dependencies
test_that("fetch_data handles API errors", {
local_mocked_bindings(
api_call = function(...) stop("Connection refused")
)
expect_error(fetch_data("endpoint"), "Connection refused")
})
test_that("fetch_data returns parsed data", {
local_mocked_bindings(
api_call = function(...) list(data = list(value = 42))
)
result <- fetch_data("endpoint")
expect_equal(result$value, 42)
})
Got: External dependencies (APIs, databases, network calls) are mocked so tests run without real connections. Mock return values exercise the function's data processing logic.
If fail: If local_mocked_bindings() fails, ensure the function being mocked is accessible in the test scope. For functions in other packages, use the .package argument.
Step 7: Snapshot Tests for Complex Output
test_that("format_report produces expected output", {
expect_snapshot(format_report(test_data))
})
test_that("plot_results creates expected plot", {
expect_snapshot_file(
save_plot(plot_results(test_data), "test-plot.png"),
"expected-plot.png"
)
})
Got: Snapshot files are created in tests/testthat/_snaps/. First run creates the baseline; subsequent runs compare against it.
If fail: If snapshots fail after an intentional change, update them with testthat::snapshot_accept(). For cross-platform differences, use the variant parameter to maintain platform-specific snapshots.
Step 8: Use Skip Conditions
test_that("database query works", {
skip_on_cran()
skip_if_not(has_db_connection(), "No database available")
result <- query_db("SELECT 1")
expect_equal(result[[1]], 1)
})
test_that("parallel computation works", {
skip_on_os("windows")
skip_if(parallel::detectCores() < 2, "Need multiple cores")
result <- parallel_compute(1:100)
expect_length(result, 100)
})
Got: Tests that require special environments (network, database, multiple cores) are guarded with skip conditions. These tests run locally but are skipped on CRAN or restricted CI environments.
If fail: If tests fail on CRAN or CI but pass locally, add the appropriate skip_on_cran(), skip_on_os(), or skip_if_not() guard at the top of the test_that() block.
Step 9: Run Tests and Check Coverage
# Run all tests
devtools::test()
# Run specific test file
devtools::test_active_file() # in RStudio
testthat::test_file("tests/testthat/test-function_name.R")
# Check coverage
covr::package_coverage()
covr::report()
Got: All tests pass with devtools::test(). Coverage report shows the target percentage is met (aim for >80%).
If fail: If tests fail, read the test output for specific assertion failures. If coverage is below target, use covr::report() to identify untested code paths and add tests for them.
Validation
- All tests pass with
devtools::test() - Coverage exceeds target percentage
- Every exported function has at least one test
- Error conditions are tested
- Edge cases are covered (NA, NULL, empty, boundary values)
- No tests depend on external state or order of execution
Pitfalls
- Tests depending on each other: Each
test_that()block must be independent - Hardcoded file paths: Use
testthat::test_path()for test fixtures - Floating point comparison: Use
expect_equal()(has tolerance) notexpect_identical() - Testing private functions: Test through the public API when possible. Use
:::sparingly. - Snapshot tests in CI: Snapshots are platform-sensitive. Use
variantparameter for cross-platform. - Forgetting
skip_on_cran(): Tests requiring network, databases, or long runtime must skip on CRAN
Examples
# Pattern: test file mirrors R/ file
# R/weighted_mean.R -> tests/testthat/test-weighted_mean.R
# Pattern: descriptive test names
test_that("weighted_mean returns NA when na.rm = FALSE and input contains NA", {
result <- weighted_mean(c(1, NA), c(1, 1), na.rm = FALSE)
expect_true(is.na(result))
})
# Pattern: testing warnings
test_that("deprecated_function emits deprecation warning", {
expect_warning(deprecated_function(), "deprecated")
})
Related Skills
create-r-package- set up test infrastructure as part of package creationwrite-roxygen-docs- document the functions you testsetup-github-actions-ci- run tests automatically on pushsubmit-to-cran- CRAN requires tests to pass on all platforms
GitHub 저장소
연관 스킬
evaluating-llms-harness
테스팅이 Claude Skill은 MMLU, GSM8K를 포함한 60개 이상의 표준화된 학술 과제에서 LLM 성능을 벤치마크하기 위해 lm-evaluation-harness를 실행합니다. 개발자들이 모델 품질을 비교하고, 학습 진행 상황을 추적하거나 학술 결과를 보고할 수 있도록 설계되었습니다. 이 도구는 HuggingFace와 vLLM 모델을 포함한 다양한 백엔드를 지원합니다.
cloudflare-cron-triggers
테스팅이 스킬은 cron 표현식을 사용하여 Worker를 스케줄링하기 위한 Cloudflare Cron Triggers 구현에 관한 포괄적인 지식을 제공합니다. 주기적 작업, 유지보수 작업, 자동화된 워크플로우 설정 방법을 다루며, 잘못된 cron 표현식이나 시간대 문제 같은 일반적인 이슈들을 해결하는 방법을 포함합니다. 개발자들은 이를 통해 스케줄된 핸들러 구성, cron 트리거 테스트, Workflows 및 Green Compute와의 연동 작업을 수행할 수 있습니다.
webapp-testing
테스팅이 Claude Skill은 Python 스크립트를 통해 로컬 웹 애플리케이션을 테스트하기 위한 Playwright 기반 툴킷을 제공합니다. 프론트엔드 검증, UI 디버깅, 스크린샷 캡처, 로그 확인 기능을 지원하며 서버 라이프사이클을 관리합니다. 브라우저 자동화 작업에 사용하되 컨텍스트 오염을 방지하기 위해 소스 코드를 읽지 않고 스크립트를 직접 실행하세요.
finishing-a-development-branch
테스팅이 스킬은 테스트 통과를 확인한 후 체계적인 통합 옵션을 제시하여 개발자가 완성된 작업을 마무리하도록 돕습니다. 구현이 완료된 후 머지, PR 생성, 브랜치 정리와 같은 워크플로우를 안내합니다. 코드가 준비되고 테스트가 완료되었을 때 개발 프로세스를 체계적으로 마무리하기 위해 사용하세요.
