agentsclimarketplace

Rust testing

Skill gurinderu/craft/skills/rust-testing

Rust testing — unit, integration, async, table-driven (rstest), property-based (proptest), fuzzing (cargo-fuzz), mutation (cargo-mutants), mocking (mockall), snapshot (insta), doc tests, and coverage. Use when writing or reviewing Rust tests, adding coverage, choosing a testing crate, or setting up CI. Triggers: #[tokio::test], rstest, proptest, cargo-fuzz, cargo-mutants, mockall, insta, nextest.From its SKILL.md

Install
npx -y skills add gurinderu/craft --skill rust-testing

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

5.3 KB, as published. Nobody here has run it

Rust Testing

Self-contained guide to testing Rust: what to reach for, the TDD loop in Rust terms, and the commands. Deep examples live in the sub-files below — read the one you need, not all three.

When to Use

  • Writing tests for new functions, methods, traits, or modules
  • Adding coverage to existing code
  • Choosing the right testing crate for a case (table-driven, property, mock, snapshot)
  • Setting up the test runner and CI for a Rust project

Pick the right tool

SituationReach forWhere
One behavior, one inputplain #[test]core.md
Function returns Result / can panic? in test / #[should_panic]core.md
Cross-crate / public API behaviorintegration test in tests/core.md
Show usage in the docsdoc test (``` in ///)core.md
Same logic, many input/output pairsrstest #[case]advanced.md
Shared setup across testsrstest #[fixture]advanced.md
async fn under test#[tokio::test]advanced.md
Invariant must hold for all inputsproptestadvanced.md
Isolate a unit from a trait dependencymockalladvanced.md
Behavior spec in Given/When/Then (or Gherkin .feature)plain test, or cucumberadvanced.md
Assert on large/structured outputinsta snapshottooling.md
Faster runs, better output, CIcargo nextesttooling.md
Prove what's testedcargo llvm-covtooling.md
Find crashes/panics on adversarial bytes (parser, untrusted input, unsafe)cargo-fuzzadvanced.md
Check tests actually catch bugs, not just runcargo-mutantstooling.md

Benchmarking (criterion, cargo bench) is not testing — it belongs to rust-performance, not here.

The TDD loop in Rust

Discipline is RED → GREEN → REFACTOR. In Rust the mechanics are:

// RED — write the test first; stub the impl with todo!() so it compiles but fails
pub fn slugify(s: &str) -> String { todo!() }

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn lowercases_and_dashes() {
        assert_eq!(slugify("Hello World"), "hello-world");
    }
}
// `cargo test` → panics at "not yet implemented" = RED
// GREEN — minimal code to pass
pub fn slugify(s: &str) -> String {
    s.to_lowercase().replace(' ', "-")
}
// `cargo test` → PASS. Now REFACTOR with the test as a safety net.

Rules that keep the loop honest:

  • Watch the test fail first — a test that was never red proves nothing.
  • One behavior per test; the name states the scenario (rejects_empty_input, not test1).
  • Tests must be independent — no shared mutable state, no ordering assumptions.

Command cheatsheet

cargo test                     # all tests (unit + integration + doc)
cargo test name_substring      # only tests whose name matches
cargo test -- --nocapture      # show println!/dbg! output
cargo test --lib               # unit tests only
cargo test --test api          # one integration binary (tests/api.rs)
cargo test --doc               # doc tests only
cargo test -- --include-ignored  # also run #[ignore] tests
cargo test --no-fail-fast      # don't stop at first failure

(For cargo nextest and coverage, see tooling.md.)

DO / DON'T

DO

  • Test behavior, not implementation details.
  • Prefer assert_eq! over assert!(a == b) — better failure messages.
  • Return Result from tests and use ? instead of unwrapping each step.
  • Put unit tests in a #[cfg(test)] mod tests next to the code; integration tests in tests/.
  • Quarantine or fix flaky tests immediately — never #[ignore] and forget.

DON'T

  • Use #[should_panic] when you could assert result.is_err() (panic tests can pass for the wrong reason).
  • Mock everything — prefer a real or in-memory implementation when feasible; mock only at true boundaries.
  • Use thread::sleep to "wait" in async tests — use tokio::time::pause/advance or channels.
  • Assert on debug-formatted blobs by hand when a snapshot (insta) is clearer.

Project defaults

This collection targets the latest stable toolchain:

[package]
edition = "2024"

Test crates are [dev-dependencies] — they never ship in the final binary.

Boundaries

This skill covers writing and running Rust tests. Adjacent concerns belong elsewhere:

  • Benchmarking and profiling (criterion, cargo bench, flamegraphs) → rust-performance.
  • Fake-port unit tests and hexagonal adapter layering (what to fake vs. integrate) → rust-architecture.
  • Deriving BDD scenarios from requirements → specs.
  • Reporting and owning skipped-test status (don't let "no Docker" pass as "covered").
  • Flagging weak or missing tests in a diff → rust-review.

Keep looking

Skills are one crate of 626,474. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.