agents/openai.yaml
interface: display_name: "Testing Craft" short_description: "Behavior-focused tests and scoped verification" default_prompt: "Use $testing-craft while writing or reviewing tests."
jssblck/agents · GitHub
Write, review, or refactor tests using behavior-focused assertions, deterministic fixtures, and verification proportional to the change. Follow the project's test conventions.
프로젝트 폴더에서 아래 명령어를 실행하고, 설치할 에이전트를 선택하세요.
npx skills add jssblck/agents --skill testing-craft설치 명령을 직접 실행해야 적용됩니다. 지원 에이전트와 필요한 권한·라이선스는 제작자의 안내를 확인하세요.
agents/openai.yamlinterface: display_name: "Testing Craft" short_description: "Behavior-focused tests and scoped verification" default_prompt: "Use $testing-craft while writing or reviewing tests."
languages/go.md# Go testing dialect
How the universal core is spelled in Go tests.
Runner: `go test ./...`; always `go test -race` in CI.
- **Table-driven tests** are the Go idiom:
```go
tests := []struct{ name, in, want string }{ ... }
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { /* got := f(tt.in); compare */ })
}
```
- Standard `testing` package; `t.Run` for subtests, `t.Helper()` in helpers,
`t.TempDir()`/`t.Cleanup()` for fixtures. `testify/require` is acceptable
for assertions; do not pull in heavy frameworks.
- No mocks of your own code. Define the small consumer interface and pass a
real test implementation, or use `httptest.Server` for HTTP, a real temp
dir/db for storage.
- Property tests via `testing/quick` or `gopter`. Fuzz tests with `go test
-fuzz`. Benchmarks with `testing.B` and `b.N`.
- Determinism: inject the clock and randomness; never `time.Sleep` to
synchronize (use channels/WaitGroup).
languages/python.md# Python testing dialect How the universal core is spelled in Python tests. Runner: `pytest`. - pytest. Plain `assert`, fixtures via `@pytest.fixture`, `tmp_path` for temp dirs, `@pytest.mark.parametrize` for table-style cases (the Python form of table-driven tests). - **Avoid `unittest.mock` of your own code.** Patching internal functions pins the implementation and rots. Prefer real objects, real `tmp_path`, a real in-memory fake you wrote, `responses`/`respx` or a local server for HTTP, a real test DB. Reserve mocking for genuine external services, and prefer a contract test against the real thing. - `hypothesis` for property-based testing (excellent, use it where inputs have invariants or round-trips). `pytest-asyncio` for async tests. - Determinism: `freezegun` or an injected clock for time; seed randomness; never `time.sleep` to synchronize, use the actual completion signal. `monkeypatch` the environment, not global state mutation.
languages/rust.md# Rust testing dialect
How the universal core is spelled in Rust tests.
Runner: `cargo test`.
- Inline `#[cfg(test)] mod tests { use super::*; }` while a module is small;
migrate a large test body to a sibling `tests.rs` (`#[cfg(test)] mod tests;`)
if test edits start forcing library recompiles.
- `#[tokio::test]` for async, `#[should_panic]` for panic paths.
- No mocks. Real pure functions, `tempfile` dirs, throwaway `git init` repos,
`sqlx::test` for Postgres. A deterministic in-memory implementation of a
trait is fine; recording mocks are not.
- `proptest` for properties, `criterion` with `black_box` for benchmarks. Keep
doctests runnable (use `?` in examples, `#` to hide setup lines).
- For internal apps prefer `src/` unit tests over many `tests/*.rs` binaries;
use at most one modular integration crate for a real external boundary.
languages/typescript.md# TypeScript / JavaScript testing dialect How the universal core is spelled in TypeScript tests. Runner: Vitest or Jest; `tsc --noEmit` is part of the test gate (a green test suite with type errors is not green). - Test behavior through the module's public surface. `vi.mock` / `jest.mock` are lint errors under the anti-slop config (`anti-slop/no-module-mocking`; see the code-craft TypeScript dialect for the lint setup); avoid `vi.spyOn` on your own functions too. Both pin implementation. Use real implementations, a real in-memory store, MSW for HTTP boundaries, real temp dirs. - `fast-check` for property-based tests. Deterministic: fake timers (`vi.useFakeTimers`) instead of real `setTimeout` waits; inject the clock and RNG. - Descriptive `describe`/`it` names that read as behavior sentences.
references/episodes.md# Testing on the Toilet episode index Source posts on the [Google Testing Blog](https://testing.googleblog.com/search/label/TotT) (2007-2026), grouped by the core section of `SKILL.md` they feed. Load this file when you need the original argument behind a rule, or a theme the skill compressed. Curation follows [`shamashel/testing-on-the-toilet`](https://github.com/shamashel/testing-on-the-toilet), which dropped meta/history posts, review etiquette, and obsolete framework how-tos. ## What to assert; change detectors (core 1, 2) - [Change-Detector Tests Considered Harmful](https://testing.googleblog.com/2015/01/testing-on-toilet-change-detector-tests.html): the source of core 2. - [Test Behavior, Not Implementation](https://testing.googleblog.com/2013/08/testing-on-toilet-test-behavior-not.html) - [Test Behaviors, Not Methods](https://testing.googleblog.com/2014/04/testing-on-toilet-test-behaviors-not.html) - [Testing State vs. Testing Interactions](https://testing.googleblog.com/2013/03/testing-on-toilet-testing-state-vs.html) - [Prefer Testing Public APIs Over Implementation-Detail Classes](https://testing.googleblog.com/2015/01/testing-on-toilet-prefer-testing-public.html) - [What Makes a Good Test?](https://testing.googleblog.com/2014/03/testing-on-toilet-what-makes-good-test.html) - [Effective Testing](https://testing.googleblog.com/2014/05/testing-on-toilet-effective-testing.html): fidelity, resilience, precision. ## Doubles and seams (core 3, 4) - [Know Your Test Doubles](https://testing.googleblog.com/2013/07/testing-on-toilet-know-your-test-doubles.html): the real/fake/stub/mock vocabulary. - [Increase Test Fidelity By Avoiding Mocks](https://testing.googleblog.com/2024/02/increase-test-fidelity-by-avoiding-mocks.html) - [Don't Overuse Mocks](https://testing.googleblog.com/2013/05/testing-on-toilet-dont-overuse-mocks.html) - [Don't Mock Types You Don't Own](https://testing.googleblog.com/2020/07/testing-on-toilet-dont-mock-types-you.html) - [Fake Your Way to Better Tests](https://testing.googleblog.com/2013/06/testing-on-toilet-fake-your-way-to.html) - [Keep Your Fakes Simple](https://testing.googleblog.com/2009/01/tott-keep-your-fakes-simple.html) - [Exercise Service Call Contracts in Tests](https://testing.googleblog.com/2018/11/testing-on-toilet-exercise-service-call.html): contract-test shared fakes. - [Only Verify State-Changing Method Calls](https://testing.googleblog.com/2017/12/testing-on-toilet-only-verify-state.html) - [Only Verify Relevant Method Arguments](https://testing.googleblog.com/2018/06/testing-on-toilet-only-verify-relevant.html) - [Stubs Speed up Your Unit Tests](https://testing.googleblog.com/2007/04/tott-stubs-speed-up-your-unit-tests.html) - [Friends You Can Depend On](https://testing.googleblog.com/2008/06/tott-friends-you-can-depend-on.html) - [Testing Against Interfaces](https://testing.googleblog.com/2008/07/tott-testing-against-interfaces.html): one shared contract test per implementation. - [Contain Your Environment](https://testing.googleblog.com/2008/10/tott-contain-your-environment.html) - [Defeat Static Cling](https://testing.googleblog.com/2008/06/defeat-static-cling.html) - [Using Dependency Injection to Avoid Singletons](https://testing.googleblog.com/2008/05/tott-using-dependancy-injection-to.html) - [Better Stubbing in Python](https://testing.googleblog.com/2007/01/better-stubbing-in-python.html): parameterize; do not patch globals. - [Partial Mocks using Forwarding Objects](https://testing.googleblog.com/2009/02/tott-partial-mocks-using-forwarding_19.html) ## Layers, risk, coverage (core 5) - [SMURF: Beyond the Test Pyramid](https://testing.googleblog.com/2024/10/smurf-beyond-test-pyramid.html) - [Risk-Driven Testing](https://testing.googleblog.com/2014/05/testing-on-toilet-risk-driven-testing.html) - [What Makes a Good End-to-End Test?](https://testing.googleblog.com/2016/09/testing-on-toilet-what-makes-good-end.html) - [Testing UI Logic? Follow the User!](https://testing.googleblog.com/2020/10/testing-on-toilet-testing-ui-logic.html) - [The Invisible Branch](https://testing.googleblog.com/2008/05/tott-invisible-branch.html): cover the implicit else. - [Understanding Your Coverage Data](https://testing.googleblog.com/2008/03/tott-understanding-your-coverage-data.html) - [Too Many Tests](https://testing.googleblog.com/2008/02/in-movie-amadeus-austrian-emperor.html): predicates over combinatorics. - [A Matter of Black and White](https://testing.googleblog.com/2008/08/progressive-developer-knows-that-in.html): must-pass cases vs. thresholded hard cases. ## Structure, data, assertions, names (core 6) - [Tests Too DRY? Make Them DAMP!](https://testing.googleblog.com/2019/12/testing-on-toilet-tests-too-dry-make.html) - [Keep Tests Focused](https://testing.googleblog.com/2018/06/testing-on-toilet-keep-tests-focused.html) - [Keep Cause and Effect Clear](https://testing.googleblog.com/2017/01/testing-on-toilet-keep-cause-and-effect.html) - [Include Only Relevant Details In Tests](https://testing.googleblog.com/2023/10/include-only-relevant-details-in-tests.html) - [Cleanly Create Test Data](https://testing.googleblog.com/2018/02/testing-on-toilet-cleanly-create-test.html) - [Choosing Values for Robust Tests](https://testing.googleblog.com/2026/06/choosing-values-for-robust-tests.html): distinct non-default values. - [Don't Put Logic in Tests](https://testing.googleblog.com/2014/07/testing-on-toilet-dont-put-logic-in.html) - [Data Driven Traps!](https://testing.googleblog.com/2008/09/tott-data-driven-traps.html) - [Writing Descriptive Test Names](https://testing.googleblog.com/2014/10/testing-on-toilet-writing-descriptive.html) - [Naming Unit Tests Responsibly](https://testing.googleblog.com/2007/02/tott-naming-unit-tests-responsibly.html) - [Prefer Narrow Assertions in Unit Tests](https://testing.googleblog.com/2024/04/prefer-narrow-assertions-in-unit-tests.html) - [Test Failures Should Be Actionable](https://testing.googleblog.com/2024/05/test-failures-should-be-actionable.html) - [How I Learned To Stop Writing Brittle Tests and Love Expressive APIs](https://testing.googleblog.com/2024/04/how-i-learned-to-stop-writing-brittle.html) - [Truth: a fluent assertion framework](https://testing.googleblog.com/2014/12/testing-on-toilet-truth-fluent.html) - [Literate Testing With Matchers](https://testing.googleblog.com/2009/09/tott-literate-testing-with-matchers.html) - [Making a Perfect Matcher](https://testing.googleblog.com/2009/10/tott-making-perfect-matcher.html) - [EXPECT vs. ASSERT](https://testing.googleblog.com/2008/07/tott-expect-vs-assert.html): keep checking after an independent failure. - [Floating-Point Comparison](https://testing.googleblog.com/2008/10/tott-floating-point-comparison.html) - [The Stroop Effect](https://testing.googleblog.com/2008/02/tott-stroop-effect.html): failure messages state expected behavior. ## Flakiness, time, isolation (core 7) - [Avoiding Flakey Tests](https://testing.googleblog.com/2008/04/tott-avoiding-flakey-tests.html) - [Sleeping != Synchronization](https://testing.googleblog.com/2008/08/tott-sleeping-synchronization.html) - [Time is Random](https://testing.googleblog.com/2008/04/tott-time-is-random.html) - [Simulating Time in jsUnit Tests](https://testing.googleblog.com/2008/10/tott-simulating-time-in-jsunit-tests.html) (earlier take: [2007-03-29](https://testing.googleblog.com/2007/03/javascript-simulating-time-in-jsunit.html)) - [Finding Data Races in C++](https://testing.googleblog.com/2008/11/tott-finding-data-races-in-c.html): ordinary tests miss races; run detectors. ## Proving tests can fail (core 9) - [Refactoring Tests in the Red](https://testing.googleblog.com/2007/04/tott-refactoring-tests-in-the-red.html) ## Testability of production code (seams; overlaps code-craft) - [Functional Core, Imperative Shell](https://testing.googleblog.com/2025/10/simplify-your-code-functional-core.html) - [Construct with Collaborators, Call with Work](https://testing.googleblog.com/2026/05/construct-with-collaborators-call-with.html) - [The Way of TDD](https://testing.googleblog.com/2026/03/the-way-of-tdd.html) - [Separation of Concerns? That's a Wrap!](https://testing.googleblog.com/2020/12/testing-on-toilet-separation-of.html) - [Avoid Hardcoding Values for Better Libraries](https://testing.googleblog.com/2020/08/testing-on-toilet-avoid-hardcoding.html) - [Make Interfaces Hard to Misuse](https://testing.googleblog.com/2018/07/code-health-make-interfaces-hard-to.html) - [Obsessed With Primitives?](https://testing.googleblog.com/2017/11/obsessed-with-primitives.html) - [Write Change-Resilient Code With Domain Objects](https://testing.googleblog.com/2024/09/write-change-resilient-code-with-domain.html) - [Don't DRY Your Code Prematurely](https://testing.googleblog.com/2024/05/dont-dry-your-code-prematurely.html) - [Avoid the Long Parameter List](https://testing.googleblog.com/2024/05/avoid-long-parameter-list.html) - [Extracting Methods to Simplify Testing](https://testing.googleblog.com/2007/06/tott-extracting-methods-to-simplify.html) - [Avoiding friend Twister in C++](https://testing.googleblog.com/2007/10/tott-avoiding-friend-twister-in-c.html) - [Web Testing Made Easier: Debug IDs](https://testing.googleblog.com/2014/08/testing-on-toilet-web-testing-made.html): stable test IDs for UI locators. - [Be an MVP of GUI Testing](https://testing.googleblog.com/2009/02/with-all-sport-drug-scandals-of-late.html) - [Testing GWT without GwtTestCase](https://testing.googleblog.com/2009/08/tott-testing-gwt-without-gwttest.html): keep UI-framework runners off business logic. - [Testable Contracts Make Exceptional Neighbors](https://testing.googleblog.com/2008/05/tott-testable-contracts-make.html) - [Prefactoring](https://testing.googleblog.com/2026/07/prefactoring-clear-way-for-your-new.html): restructure first, then add the feature. - [In Praise of Small Pull Requests](https://testing.googleblog.com/2024/07/in-praise-of-small-pull-requests.html)
SKILL.md--- name: testing-craft description: Write, review, or refactor tests using behavior-focused assertions, deterministic fixtures, and verification proportional to the change. Follow the project's test conventions. user-invocable: true argument-hint: "[rust|typescript|go|python] [target]" --- # Testing Craft Choose tests for the defects they catch. Preserve useful regression coverage without binding tests to incidental implementation details. ## Scope and verification - Identify the behavior being changed and the specific defect each new or modified test should catch. A test need not detect unrelated defects. - Follow project instructions and existing test conventions over these defaults. - Run affected tests and required checks. Broaden coverage when the change's dependencies, failures, or unresolved risks justify it. - Do not change production architecture merely to satisfy a testing preference. Restructure when needed for the requested fix; propose independent refactors. - Read only the relevant language file below when runner or fixture guidance is needed. General code guidance lives in `code-craft`. ## Choose the boundary and layer Prefer inputs and observable outputs through the feature's public boundary. Private helpers can merit direct tests for substantial algorithms or invariants; do not make them public solely for testing. Use the cheapest layer that catches the risk: | Risk | Suitable starting point | |---|---| | Parsing, pure logic, state transitions | Unit test | | Collaboration between components | Real objects or a maintained fake | | Service or HTTP contract | Integration test with a hermetic server or contract-tested fake | | UI wiring | Drive the rendered control rather than calling its handler | | Cross-system behavior | Focused end-to-end test | Use existing automation when it covers the changed behavior. Manual exercise is useful when it catches a risk that automation does not, such as visual layout. ## Avoid implementation-mirroring tests Source-text assertions and exact internal call scripts often pin an implementation without protecting its contract. For a suspect test, identify: - The behavior it protects. - A concrete defect that would make it fail. - Whether it rejects a valid implementation with the same behavior. Rewrite brittle assertions to check results, state, rendered output, or external effects. Remove a test only when it has no useful contract to protect or its coverage is redundant. A test passing while some other behavior breaks is not a reason to delete it. Interaction assertions are useful when the interaction is itself the contract, such as sending one email, avoiding a network request on a cache hit, or checking authorization before a write. Assert only the relevant calls and arguments. ## Choose collaborators Prefer the real implementation when it is fast, deterministic, and isolated. Use temporary directories, throwaway repositories, or local servers where useful. When the real dependency is unsuitable: - Use a narrow working fake for stateful behavior. Check shared fakes against the real contract where practical. - Use a stub for canned query results or to force a failure. - Use a mock for interactions whose occurrence, absence, or order is the contract. Avoid elaborate mock setups that duplicate implementation details. A wrapper around a third-party dependency can provide a stable seam, but do not add one solely to obey a ban on mocking types you do not own. Use the project's existing seams and library-supported testing tools when they fit. ## Write readable tests - Name the scenario and expected outcome. Keep cause and effect visible. - Keep relevant inputs and expectations in the test body. Helpers may hide irrelevant construction; table-driven cases are useful for parallel scenarios. - Do not compute expected results by repeating the production algorithm. - Choose distinct values that expose swapped inputs or accidental defaults. Include empty, zero, and boundary values when those are the behavior under test. - Assert the fields that matter. Use full-object equality when the whole object is the contract, rather than a broad snapshot of incidental details. - Make failures show expected and actual values. - Cover relevant failure paths and boundaries. Use property tests when invariants or a large input space justify them, not merely because a library is available. ## Keep tests deterministic - Wait for completion signals or observable conditions with a timeout; do not sleep for an arbitrary duration and assume work finished. - Control time and randomness when they affect the result. - Isolate mutable state between tests. - Make important failures reproducible through a controlled dependency or input. ## Establish regression sensitivity For a bug fix, reproduce the actual failure before changing production code when feasible. Confirm the regression test fails for the intended reason, then passes with the fix. For other changes, identify the defect the assertion detects. Use targeted mutation when sensitivity is uncertain or the risk warrants it. If mutating production code, isolate the experiment and restore it before continuing. Inverting an assertion checks execution, not sensitivity to the intended defect. Routine test edits and green-to-green refactors do not require production mutations. Preserve the behaviors covered and compare relevant results before and after a refactor. Report verification you could not perform. ## Language references Read the relevant file when runner, fixture, or async-test details are needed: - [Rust](languages/rust.md) - [TypeScript / JavaScript](languages/typescript.md) - [Go](languages/go.md) - [Python](languages/python.md) For other languages, follow the project's conventions. ## Provenance Adapted from Google's Testing on the Toilet series, including behavior-focused tests, test doubles, DAMP, and SMURF. The source episodes are indexed in [references/episodes.md](references/episodes.md), by way of [shamashel/testing-on-the-toilet](https://github.com/shamashel/testing-on-the-toilet).