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

rust-testing

Use when writing tests for Rust service code - unit tests beside the code, integration tests in tests/, tokio::test, Router::oneshot for HTTP, sqlx::test for a fresh database per test, trait fakes or mockall at ports, test-first

インストール方法を見る

含まれるファイル(1)

  • SKILL.md4.2 KB

SKILL.md(原文)

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

Rust Testing

Overview

Test-first, same discipline as everywhere (see tdd-workflow): write the failing test, watch it fail, minimal code to pass. This skill is the Rust mechanics for a service.

Core principle: the type system already rules out a lot; tests cover behaviour, invariants and the boundaries the compiler cannot see — HTTP wiring, serialization and SQL.

Test levels

LevelWhat it coversTools
UnitDomain types and pure functions#[cfg(test)] mod tests in the same file, #[test]
Unit with fakesService, its port traits fakeda hand-written fake struct, or mockall where the repository uses it
HTTPRouting, extractors, status codes, error bodythe Router called with tower::ServiceExt::oneshot — no port
Persistencesqlx queries and migrations#[sqlx::test]: a fresh database per test with migrations applied

Integration tests that use the crate's public API go in tests/.

Unit and service tests

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn title_rejects_blank_and_overlong() {
        for bad in ["", "   ", &"x".repeat(201)] {
            assert!(TaskTitle::try_from(bad.to_string()).is_err(), "{bad:?} should be rejected");
        }
        assert!(TaskTitle::try_from("x".repeat(200)).is_ok());
    }

    #[tokio::test]
    async fn create_stores_the_task() {
        let repo = FakeTaskRepo::default();
        let service = TaskService::new(repo.clone());
        let task = service.create(UserId::new(1), TaskTitle::try_from("Report".into()).unwrap()).await.unwrap();
        assert_eq!(repo.stored(), vec![task]);
    }
}

unwrap() is fine in tests: a panic is a failure with a line number.

HTTP without a port

#[tokio::test]
async fn blank_title_is_400_in_the_problem_shape() {
    let app = router(test_state());
    let res = app
        .oneshot(Request::post("/tasks").header("content-type", "application/json")
            .header("authorization", test_token(1)).body(Body::from(r#"{"title":""}"#)).unwrap())
        .await
        .unwrap();
    assert_eq!(res.status(), StatusCode::BAD_REQUEST);
    let body: serde_json::Value = serde_json::from_slice(&res.into_body().collect().await.unwrap().to_bytes()).unwrap();
    assert!(body["errors"]["title"].is_string());
}

Rules

  • Fakes at trait boundaries. A hand-written fake (a struct with an Arc<Mutex<Vec<_>>>) is often clearer than a mock; mockall's #[automock] where the repository already uses it. Never fake the type under test.
  • Boundary tables as a loop over cases with a message per case, or rstest's #[case] where the repository uses it.
  • #[sqlx::test] for anything that runs SQL: each test gets its own database with the migrations applied, so tests run in parallel without sharing rows. It needs DATABASE_URL pointing at a server it may create databases on (a container in CI and locally).
  • Time: inject a clock trait, or use tokio::time::pause() + advance() in #[tokio::test(start_paused = true)] for timers; never a real sleep.
  • Property tests (proptest) for parsers and invariants with large input spaces, where the repository has them.
  • Focused run while iterating: cargo test title_rejects or cargo test -p <crate> --test <file>; the full cargo test (all features the CI uses) plus cargo clippy --all-targets -- -D warnings before you stop. Coverage with cargo llvm-cov; mutation testing, where the repository runs it, is cargo mutants.

Common Mistakes

  • Testing only the happy path because the types "already guarantee" the rest.
  • A test that shares a database between cases and depends on run order.
  • #[ignore] on a failing test instead of fixing it.
  • Asserting on Debug output strings rather than values.

Red Flags

  • The test compiles and passes before the production code exists.
  • A unit test that needs a running database or network.
  • std::thread::sleep in a test to wait for a task.

レビュー

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

同じリポジトリのスキル

概要と使いどころ

Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases

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

makifbaysal/tasktrooper1152026年10月17日 更新

Use when the diff adds or changes an endpoint, resolver, RPC, job or query that takes an object id, a role check, a request binding or a tenant filter - BOLA/IDOR, function-level authorization, mass assignment and tenant scoping

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

makifbaysal/tasktrooper1152026年10月17日 更新

Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal

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

makifbaysal/tasktrooper1152026年10月17日 更新

Use when a task changes any screen, form, dialog, menu or control - Lighthouse/axe scan of the changed screens, a keyboard walk, and the thresholds that fail a task

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

makifbaysal/tasktrooper1152026年10月17日 更新

How to work a task returned with review, QA or UAT findings. Use when a task is in need_revision or PR review comments are in your context.

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

makifbaysal/tasktrooper1152026年10月17日 更新

Use when deciding whether a request needs an analiz task before implementation - the conditions that require the architect's analysis versus going straight to implementation

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

makifbaysal/tasktrooper1152026年10月17日 更新

makifbaysal のスキルをすべて見る

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