Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
Comprehensive Rust testing — unit/integration/doc tests, cargo test & nextest, fixtures, async (tokio::test), property testing (proptest/quickcheck), snapshots (insta), mocking (mockall), coverage (llvm-cov), benchmarks (criterion), fuzzing (cargo-fuzz), miri, mutation testing (cargo-mutants), and FFI/cross-language parity. Use when writing, organizing, debugging, or speeding up Rust tests, choosing a testing crate, or wiring test CI. Triggers — "rust test", "cargo test", "#[tokio::test]", "proptest", "insta snapshot", "mockall", "criterion bench", "cargo-nextest", "llvm-cov coverage", "miri", "cargo-fuzz", "cargo-mutants", "flaky test", "test FFI/cdylib", "doc test". NOT for non-Rust testing, general Rust syntax/borrow-checker help (use rust-with-claude-code), GPUI/pd-console specifics (use gpui-rust-console), or writing production app code.
license
Apache-2.0
allowed-tools
Read, Write, Edit, Bash, Grep, Glob
metadata
{"category":"Code Quality & Testing","tags":["rust","testing","tokio","proptest","insta","mockall","criterion","coverage","miri","fuzzing","mutation-testing","ffi-parity"],"provenance":{"kind":"first-party","owners":["port-daddy"]},"pairs-with":[{"skill":"rust-debugging-mastery","reason":"A flaky test or a parity check that passes for the wrong reason needs lldb/tracing/miri to root-cause, not another retry."},{"skill":"rust-with-claude-code","reason":"Generic Rust toolchain/workflow (borrow checker, compiler errors, session checklist) lives there; this skill assumes compiling Rust and focuses on testing it well."},{"skill":"rust-data-structures-advanced","reason":"\"Hard to test\" is often an Rc<RefCell>/ownership problem in disguise — extracting a pure, testable core frequently means adopting an arena or generational-index structure from there."},{"skill":"gpui-rust-console","reason":"pd-console's fast test suite (repl binary, no gpui, Homebrew node ABI) is a concrete domain instance of this skill's test-organization and CI-matrix guidance."}],"io-contract":{"kind":"deliverable","consumes":["[Truncated]","[Truncated]"],"produces":["[Truncated]","[Truncated]"]}}
Rust Code Testing
Write Rust tests that catch real bugs, run fast, and stay honest — and choose the
right tool from the broad Rust testing ecosystem instead of reaching for
assert_eq! and a mock every time.
When to Use
✅ Use for:
Writing unit / integration / doc tests; deciding where a test belongs
Choosing a testing crate (proptest, insta, mockall, rstest, criterion, …)
Writing the production feature itself (this skill is about its tests)
Designing the kernel/FFI boundary's ABI, ownership, or ffi-safety contract itself
(once a rust-kernel-ffi skill exists, that owns the design) — this skill tests
whatever Rust code sits on either side of that boundary, including asserting the
native kernel actually loaded before trusting a cross-language parity test
First move every session
Get fast signal before writing anything. The bundled script runs the full gate
matrix (fmt → clippy → test → doc tests → optional coverage), cheapest first:
State your status in one line before proceeding: "fmt clean, clippy clean, 22
tests green" — it anchors every later decision.
run_test_matrix.sh runs real tests against real code. Before that code
exists, audit the plan instead — scripts/test_plan_audit.mjs checks a JSON
test plan for this skill's shibboleths (coverage theater, #[test] on async
fn, mock echo, sleep-faked determinism, writes, an unasserted parity
kernel-load, dev-dependency misplacement) before you write a single test:
flowchart TD
W[What are you testing?] --> A{Private internals of one module?}
A -->|Yes| Unit["#[cfg(test)] mod tests, same file (sees private via use super::*)"]
A -->|No| B{Public API across modules?}
B -->|Yes| Integ["tests/ dir — separate crate, public API only"]
B -->|No| C{Example in a /// doc comment?}
C -->|Yes| Doc["doc test — cargo test --doc; verified documentation"]
C -->|No| Bench["benches/ (criterion) — NOT in the test gate"]
Full layout, the three-states rule (empty/populated/error), fixtures, and the
crate-type nuance (rlib vs cdylib vs bin) → references/organization-and-fixtures.md.
Which testing tool for which need?
flowchart TD
N[What kind of assurance?] --> EX{Specific input → output?}
EX -->|Yes| Plain["plain #[test] + assert_eq! on the VALUE"]
EX -->|No| INV{For-all-inputs invariant?}
INV -->|Yes| Prop["proptest / quickcheck"]
INV -->|No| SNAP{Large structured output?}
SNAP -->|Yes| Insta["insta snapshots (redact volatile fields)"]
SNAP -->|No| DEP{Expensive/nondeterministic dependency?}
DEP -->|clock/RNG| Inject["inject it as a param (pure core) — not a mock"]
DEP -->|network/DB| Mock["in-memory impl of a port; mockall only if needed"]
Plain --> ASYNC{async?}
ASYNC -->|Yes| Tok["#[tokio::test] + a timeout — never #[test] on async fn"]
Novice: "It returns Ok, so assert!(result.is_ok()) proves it works — and
coverage is 95%."
Expert: is_ok()/is_some()/len() > 0 pass regardless of correctness.
Assert the specific value, error variant, or shape. Line coverage measures
execution, not verification — 95% coverage with surviving mutants means the lines
run but nothing checks them. Prove it with cargo-mutants: a surviving mutant is
an unasserted behavior.
Detection: tests whose only assertions are is_ok/is_some/is_empty/> 0,
or that re-assert a value a mock was told to return (mock echo).
#[test] on an async fn
Novice: "It's a test, so #[test] async fn."
Expert: #[test] can't drive a future — it won't compile, or the body never
runs. Use #[tokio::test] (or #[async_std::test]), and wrap anything that
could block in tokio::time::timeout so a hung future fails instead of wedging
the whole suite.
Detection: #[test] directly above async fn; suites that hang instead of
failing.
The parity test that secretly tests nothing
Novice: "Rust and the TS fallback agree in my Jest parity test — parity
proven."
Expert: If the dylib didn't load in the harness, both sides ran the same
fallback and agreed trivially. Loaders frequently fail in the unit harness while
working in the real runtime (koffi under Jest's transformed ESM can't load a
.dylib that loads fine under Bun/tsx). Assert the kernel is loaded before
asserting parity, make "not loaded" a loud skip, and verify real parity under the
real runtime (a tsx/bun script or a Rust integration test that loads the
cdylib).
Timeline: pre-2023 FFI bindings were simpler; 2024-2026 multi-runtime
(Node/Bun/Deno) + transformed-ESM test harnesses made "passes in the harness,
breaks under the real loader (and vice-versa)" a routine trap.
Detection: a green cross-language parity test with no assertion that the
native impl is actually loaded. See references/ffi-and-cross-language-parity.md.
"Hard to test" treated as a test problem
Novice: "This function is hard to unit-test, so I need a heavier mock / a real
DB in the test."
Expert: Hard-to-test is a code-shape signal. If the unit test needs a
running daemon, a DB, or the network, infrastructure has leaked into the logic.
Extract a pure core (inject clock/IO/readings as parameters) and unit-test that
exhaustively; leave a thin, barely-tested shell for the I/O. The pure core also
becomes reusable across a CLI, a daemon, and an FFI export.
Detection: tests that spin up servers/DBs to check business logic; functions
that call Instant::now() / std::fs / a socket and make decisions.
Test-only crates in [dependencies]
Novice: "I added proptest/criterion/mockall to [dependencies]."
Expert: They belong in [dev-dependencies] — otherwise they compile into and
bloat (or break) the release binary. #[cfg(test)]-gate mock derives too
(#[cfg_attr(test, automock)]).
Detection: proptest, criterion, mockall, insta, rstest,
tempfile under [dependencies].
Mock echo: testing the mock, not the code
Novice: "The mock returns 42 and the test asserts 42 — green."
Expert: That asserts the mock framework works, not your logic. Prefer
injecting a real trivial impl (an in-memory repo, a fixed now: u64). Reach for
mockall only when the real dependency is genuinely expensive or
non-deterministic, and then assert on what your code does with the value, not
the value itself.
Detection: expect_*().returning(|| X) paired with assert_eq!(result, X).
Faking determinism with sleeps and retries
Novice: "The async test is flaky, so I added sleep(200ms) / a retry."
Expert: A sleep races the scheduler and a retry hides the bug while slowing
the suite. Await a real readiness signal (a channel recv), pause the clock
(#[tokio::test(start_paused=true)]), or isolate the shared resource (random
port, tempfile, #[serial]). Flakiness is a defect to root-cause, not smooth
over. See references/async-and-concurrency.md.
Detection: thread::sleep/tokio::time::sleep used to "let it finish";
retry wrappers around assertions; two tests binding the same fixed port.
Writing test scratch to /tmp
Novice: "Tests need a temp file, so /tmp/mytest.json."
Expert: /tmp is purged out from under you and shared across parallel test
processes (cross-test clobber + vanishing fixtures). Use tempfile::tempdir()
(auto-cleaned) or a repo-local scratch dir. Honor $TMPDIR/an env override in
helpers rather than hardcoding a path.
Detection: string literals containing /tmp/ in test code or fixtures.
Stronger assurance (opt-in, per risky module)
Escalate beyond cargo test when warranted — run these as dedicated CI jobs, not
every commit:
Tool
Catches
When
miri
undefined behavior
any crate with unsafe/raw ptrs/FFI
cargo-fuzz
panics on untrusted input
parsers, decoders, FFI parse steps
cargo-mutants
tests that don't catch bugs
core logic modules; coverage-theater audit
ASan/TSan
heap corruption / data races
unsafe/FFI; concurrent code
Details, commands, and the escalation order → references/advanced-verification.md.
References
Lazy-load only the file relevant to the current step:
File
Consult when
references/testing-crates.md
Choosing/using proptest, insta, mockall, rstest, criterion, etc.
README.md — Rust Code Testing — Write Rust tests that catch real bugs, run fast, and stay honest — and choose the right tool from the broad Rust testing ecosystem instead o
examples/expected-output.md — Example Output: Test Plan Audit — Scenario: Before writing tests for a launchd PATH-resolution fallback (bin_resolver.rs) and a daemon-restart integration test, the pla
references/advanced-verification.md — Advanced verification: miri, fuzzing, mutation, sanitizers — Consult when ordinary tests pass but you need stronger assurance — UB detection, input-space exploration, or proof your tests actually catch
references/async-and-concurrency.md — Testing async & concurrent Rust — Consult when testing async fn, futures, channels, shared-state concurrency, or chasing a flaky test.
references/coverage-ci-and-tooling.md — Coverage, runners & CI for Rust tests — Consult when measuring coverage, speeding up the suite, or wiring tests into CI.
references/ffi-and-cross-language-parity.md — Testing FFI boundaries & cross-language parity — Consult when a Rust crate is called over a C ABI (from Node/Bun via koffi/napi, Python via cffi/PyO3, etc.), or when the same logic exists i
references/organization-and-fixtures.md — Test organization, fixtures & the testability that precedes them — Consult when deciding where a test goes, building fixtures/helpers, or when code is "hard to test" (the real problem is usually the code's s
references/testing-crates.md — Rust Testing Crates — selection & idioms — Consult when choosing a testing dependency or writing tests that need more than assert_eq!.
templates/output-template.md — Rust Test Suite Design Template — [One-sentence description of the module/feature under test.] - Unit tests (private internals, #[cfg(test)] mod tests in-file): [list] - In