本文へ移動
cccskills
無料GitHub で公開

rust-testing-code-review

Reviews Rust test code for unit test patterns, integration test structure, async testing, mocking approaches, and property-based testing. Covers Rust 2024 edition changes including async fn in traits for mocks,

インストール方法を見る

含まれるファイル(5)

  • SKILL.md14.1 KB
  • references/advanced-testing.md21.5 KB
  • references/concurrency-testing.md16.4 KB
  • references/integration-tests.md8.8 KB
  • references/unit-tests.md12.6 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Rust Testing Code Review

Review Workflow

  1. Check Rust edition — Note edition in Cargo.toml (2021 vs 2024). Edition 2024 changes temporary scoping in if let and tail expressions, and makes #[expect] the preferred lint suppression
  2. Check test organization — Unit tests in #[cfg(test)] modules, integration tests in tests/ directory
  3. Check async test setup — #[tokio::test] for async tests, proper runtime configuration. Check for async-trait on mocks that could use native async fn in traits
  4. Check assertions — Meaningful messages, correct assertion type. Review if let assertions for edition 2024 temporary scope changes
  5. Check test isolation — No shared mutable state between tests, proper setup/teardown. Prefer LazyLock over lazy_static!/once_cell for shared fixtures
  6. Check coverage patterns — Error paths tested, edge cases covered

Gates (hard)

Do not advance to Output Format until each pass condition is satisfied (yes/no with a concrete artifact).

  1. Edition recorded — Open the target crate’s Cargo.toml (or workspace [workspace.package] / inherited edition) and note the edition value. Pass: you can quote edition = "…" (or document “inherited from workspace”) before citing Rust 2024–specific behavior (if let / tail temporary drops, #[expect] vs #[allow] migration, native async fn in traits as default). If edition is not 2024, do not report those items as edition-2024 regressions; at most Informational if still useful.
  2. dyn vs static async mocks — Before suggesting native async fn in traits instead of async-trait, check whether the mock is used as dyn Trait. Pass: if dyn is required, you either skip that suggestion or align with Valid Patterns (async-trait still needed).
  3. Verification protocol — Pass: steps from the review-verification-protocol skill are done before any finding is listed (see Before Submitting Findings).

Output Format

Report findings as:

[FILE:LINE] ISSUE_TITLE
Severity: Critical | Major | Minor | Informational
Description of the issue and why it matters.

Quick Reference

Issue TypeReference
Unit tests, assertions, naming, snapshots, rstest, doc tests, #[expect], LazyLock fixtures, tail expression scopereferences/unit-tests.md
Integration tests, async testing, fixtures, test databases, native async fn mocks, if let temporary scopereferences/integration-tests.md
Fuzzing, proptest, Miri, Loom basics, mocking strategies, stub/fake/mock/spy taxonomy, rstest matrix, paste!, build.rs test gen, criterion baselines + black_box discipline, trybuild UI tests, clippy lint groupsreferences/advanced-testing.md
Loom interleaving tests, Miri UB checks, shuttle, ThreadSanitizer, CI matrix for concurrent codereferences/concurrency-testing.md

Review Checklist

Test Structure

  • Unit tests in #[cfg(test)] mod tests within source files
  • Integration tests in tests/ directory (one file per module or feature)
  • use super::* in test modules to access parent module items
  • Test function names describe the scenario: test_<function>_<scenario>_<expected>
  • Tests are independent — no reliance on execution order

Async Tests

  • #[tokio::test] used for async test functions
  • #[tokio::test(flavor = "multi_thread")] when testing multi-threaded behavior
  • No block_on inside async tests (use .await directly)
  • Test timeouts set for tests that could hang
  • Mock traits use native async fn instead of async-trait crate (stable since Rust 1.75)

Assertions

  • assert_eq! / assert_ne! used for value comparisons (better error messages than assert!)
  • Custom messages on assertions that aren't self-documenting
  • matches! macro used for enum variant checking
  • Error types checked with matches! or pattern matching, not string comparison
  • One assertion per test where practical (easier to diagnose failures)
  • if let assertions reviewed for edition 2024 temporary scope — temporaries in conditions drop earlier, may invalidate borrows
  • Tail expression returns reviewed for edition 2024 — temporaries in tail expressions drop before local variables

Mocking and Test Doubles

  • Traits used as seams for dependency injection (not concrete types)
  • Mock implementations kept minimal — only what the test needs
  • No mocking of types you don't own (wrap external dependencies behind your own trait)
  • Test fixtures as helper functions, not global state
  • std::sync::LazyLock used for shared test fixtures instead of lazy_static! or once_cell (stable since Rust 1.80)

Error Path Testing

  • Result::Err variants tested, not just happy paths
  • Specific error variants checked (not just "is error")
  • #[should_panic] used sparingly — prefer Result-returning tests

Lint Suppression in Tests

  • #[expect(lint)] used instead of #[allow(lint)] for test-specific suppressions (stable since Rust 1.81)
  • Justification comment on every #[expect] or #[allow] in test code
  • Stale #[allow] attributes migrated to #[expect] for self-cleaning behavior

Test Naming

  • Test names read like sentences describing behavior (not test_happy_path)
  • Related tests grouped in nested mod blocks for organization
  • Test names follow pattern: <function>_should_<behavior>_when_<condition>

Snapshot Testing

  • cargo insta used for complex structural output (JSON, YAML, HTML, CLI output)
  • Snapshots are small and focused (not huge objects)
  • Redactions used for unstable fields (timestamps, UUIDs)
  • Snapshots committed to git in snapshots/ directory
  • Simple values use assert_eq!, not snapshots

Parametrized Testing

  • rstest used to avoid duplicated test functions for similar inputs
  • #[rstest] with #[case::name] attributes for descriptive parametrized tests
  • #[fixture] used for shared test setup when multiple tests need same construction
  • Parametrized tests still have descriptive case names (not just #[case(1)])
  • Combined with async: #[rstest] #[tokio::test] for async parametrized tests

Doc Tests

  • Public API functions have /// # Examples with runnable code
  • Doc tests serve as both documentation and correctness checks
  • Hidden setup lines prefixed with # to keep examples clean
  • cargo test --doc passes (nextest doesn't run doc tests)

Concurrency Testing

Detailed guidance: references/concurrency-testing.md

  • Hand-rolled atomics / unsafe impl Send|Sync / state machines have a #[cfg(loom)] test using loom::sync and loom::thread shims (not std::sync)
  • Crates with unsafe touching atomics, pointers, or UnsafeCell run cargo +nightly miri test --all-features in CI on every PR (not release-only, not module-level cfg_attr(miri, ignore))
  • Lock-free data structures (AtomicPtr stacks/queues/lists) have loom + Miri (Stacked Borrows and Tree Borrows) + proptest-driven operation sequences
  • Nondeterministic inputs (Instant::now, rand, env, HashMap iteration) are kept out of loom::model bodies
  • Loom jobs run in --release with a LOOM_MAX_PREEMPTIONS bound; loom tests live in a separate tests/ file so --cfg loom does not poison normal cargo test
  • nextest run -j1 is not cited as evidence of race-condition coverage; FFI-heavy unsafe extern "C" paths have a ThreadSanitizer job

Test Augmentation (Fakes, Mocks, Stubs, Spies)

Detailed guidance: references/advanced-testing.md

  • Test doubles are typed by purpose: stub (canned data), fake (working but simplified impl), mock (pre-programmed expectations + verification), spy (records calls for after-the-fact inspection) — vocabulary is used precisely
  • mockall-style mocks are not used where a fake would be simpler (in-memory DB beats expectation-heavy mocks for repository-style traits)
  • Fakes are tested against the same contract as the production impl (trait conformance test); no drift
  • Trait-as-seam pattern used to inject test doubles — production code depends on the trait, not the concrete type

Performance Tests (Criterion)

Detailed guidance: references/advanced-testing.md

  • Benchmarks use criterion::black_box(...) to prevent constant-folding; pointer-flavored inputs use black_box(input.as_ptr()) not black_box(&input)
  • Benchmarks isolate I/O — setup (file open, allocation) in iter_batched setup closure, NOT inside the measured closure
  • CI persists a baseline via cargo bench -- --save-baseline main; feature branches compare with --baseline main; regression threshold defined and enforced
  • Criterion benchmarks build with --profile bench (release optimization + debug symbols for flamegraph correlation)
  • No #[bench] (unstable, deprecated) — use criterion exclusively
  • Single-shot timings are not cited as evidence; reports show mean + variance from criterion's statistical engine

Test Generation

Detailed guidance: references/advanced-testing.md

  • Table-driven inputs use rstest with #[case::name(...)] (descriptive case names in test output)
  • Multi-axis input matrices use rstest with #[values(...)] on multiple parameters (Cartesian product), not hand-expanded test functions
  • Per-input-named tests for large corpora use paste! macro or build.rs codegen (one #[test] fn per file/case)
  • Generated tests have stable names that survive CI log diffs

Proc-Macro UI Tests (trybuild)

Detailed guidance: references/advanced-testing.md

  • Proc-macros that emit compile errors have trybuild::TestCases covering each failure path with a .stderr reference
  • .stderr outputs were regenerated after the latest rustc bump (otherwise spurious CI failures); TRYBUILD=overwrite cargo test is documented in CONTRIBUTING
  • CI pins a specific stable rustc for trybuild jobs (the .stderr format shifts between stable releases)
  • trybuild tests skipped on nightly (nightly diagnostics differ from stable)

Clippy Lint Group Strategy

Detailed guidance: references/advanced-testing.md

  • clippy::correctness is deny (always — these are bugs)
  • clippy::suspicious is warn or deny for libraries
  • clippy::perf is warn (real wins on hot paths)
  • clippy::pedantic enabled for libraries; suppressions use #[expect(clippy::lint_name, reason = "...")] with justification, not bare #[allow]
  • clippy::nursery is NOT enabled in CI (experimental; changes between rustc releases)
  • clippy::restriction lints are opt-in individually; the group is never enabled wholesale

Severity Calibration

Critical

  • Tests that pass but don't actually verify behavior (assertions on wrong values)
  • Shared mutable state between tests causing flaky results
  • Missing error path tests for security-critical code

Major

  • #[should_panic] without expected message (catches any panic, including wrong ones)
  • unwrap() in test setup that hides the real failure location
  • Tests that depend on execution order
  • if let with inline temporary in assertion that breaks under edition 2024 temporary scoping
  • async-trait on mock traits when native async fn in traits is available and project targets edition 2024

Minor

  • Missing assertion messages on complex comparisons
  • assert!(x == y) instead of assert_eq!(x, y) (worse error messages)
  • Test names that don't describe the scenario
  • Redundant setup code that could be extracted to a helper
  • #[allow] used where #[expect] would provide self-cleaning suppression
  • lazy_static! or once_cell used for test fixtures when LazyLock is available

Informational

  • Suggestions to add property-based tests via proptest or quickcheck
  • Suggestions to add snapshot testing for complex output
  • Coverage improvement opportunities

Valid Patterns (Do NOT Flag)

  • unwrap() / expect() in tests — Panicking on unexpected errors is the correct test behavior
  • use super::* in test modules — Standard pattern for accessing parent items
  • #[allow(dead_code)] on test helpers — Helper functions may not be used in every test
  • clone() in tests — Clarity over performance
  • Large test functions — Integration tests can be long; extracting helpers isn't always clearer
  • assert! for boolean checks — Fine when the expression is clearly boolean (.is_some(), .is_empty())
  • Multiple assertions testing one logical behavior — Sometimes one behavior needs multiple checks
  • unwrap() on Result-returning test functions — Propagating with ? is also fine but not required
  • async-trait on mock traits requiring dyn dispatch — Native async fn in traits doesn't support dyn Trait; async-trait is still needed there
  • #[expect] with justification on test helpers — Self-cleaning lint suppression is correct in test code
  • LazyLock for expensive shared test fixtures — Thread-safe lazy init is appropriate for test globals

Before Submitting Findings

Load and follow the review-verification-protocol skill before reporting any issue.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Use when you need to mine a conversation, session transcript, or design discussion for architectural decisions before writing ADRs. Identifies problem-solution pairs, trade-off debates, technology choices, and explicit "[ADR]" tags. Triggers on "what decisions did we make", "extract decisions from this chat", "find the choices in our discussion", or "summarize architectural decisions". Also useful after long planning sessions to capture decisions that were made implicitly. Does NOT write ADR documents — use adr-writing or write-adr for that.

日本語の概要は準備中です。原文の説明を表示しています。

existential-birds/beagle822026年9月16日 更新

Use when writing or formatting an ADR document using the MADR template, applying Definition of Done (E.C.A.D.R.) criteria, or verifying ADR completeness. Triggers on "write the ADR", "format as MADR", "check ADR quality", "mark gaps in ADR". Also triggers when a decision has been extracted and needs to become a document. Does NOT extract decisions from conversations (use adr-decision-extraction) or orchestrate the full extract-confirm-write workflow (use write-adr).

日本語の概要は準備中です。原文の説明を表示しています。

existential-birds/beagle822026年9月16日 更新

Use when auditing an agent codebase against the 12-Factor Agents methodology, reviewing LLM-powered system architecture, or assessing agentic app compliance. Triggers on "analyze agent architecture", "12-factor audit", "how compliant is this agent", or "evaluate this LLM app". Also applies when comparing frameworks or planning agent improvements. Not for quick checklists — this performs deep per-factor codebase analysis with file-level evidence.

日本語の概要は準備中です。原文の説明を表示しています。

existential-birds/beagle822026年9月16日 更新

Vercel AI Elements for workflow UI components. Use when building chat interfaces, displaying tool execution, showing reasoning/thinking, or creating job queues. Triggers on ai-elements, Queue, Confirmation, Tool, Reasoning, Shimmer, Loader, Message, Conversation, PromptInput.

日本語の概要は準備中です。原文の説明を表示しています。

existential-birds/beagle822026年9月16日 更新

Reviews App Intents code for intent structure, entities, shortcuts, and parameters. Use when reviewing code with import AppIntents, @AppIntent, AppEntity, AppShortcutsProvider, or @Parameter.

日本語の概要は準備中です。原文の説明を表示しています。

existential-birds/beagle822026年9月16日 更新

Use when the user wants a cited, structured read of local documents and project knowledge. Triggers on: "analyze these docs", "scan my project for context", "read the docs folder", "summarize what's in .beagle/concepts/", "extract context from docs/", "what's in this folder", "go read everything in X and tell me what's there". Also invoked programmatically by other beagle skills (prfaq-beagle Ignition, brainstorm-beagle reference points, strategy-interview context grounding) via the companion contract. Does NOT trigger on codebase lookups ("find this function", "search the repo"), web research (use web-research), LLM-as-judge evaluation (use llm-judge), or document editing (use humanize-beagle). Produces a written scan plan, parallel-subagent findings, and a cited synthesis report on disk — never inline prose, never unsourced claims.

日本語の概要は準備中です。原文の説明を表示しています。

existential-birds/beagle822026年9月16日 更新

existential-birds のスキルをすべて見る

このスキルの問題を報告する