본문으로 건너뛰기
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.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

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

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

makifbaysal/tasktrooper1172026년 10월 18일 업데이트

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/tasktrooper1172026년 10월 18일 업데이트

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

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

makifbaysal/tasktrooper1172026년 10월 18일 업데이트

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/tasktrooper1172026년 10월 18일 업데이트

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/tasktrooper1172026년 10월 18일 업데이트

Use when the repository keeps its alerting in code, or a person asks for alerts outside TaskTrooper - PrometheusRule YAML, a Cloud Monitoring alert policy in Terraform, a Datadog monitor, each routed to TaskTrooper's alert ingest URL so it opens an incident here

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

makifbaysal/tasktrooper1172026년 10월 18일 업데이트

makifbaysal의 스킬 모두 보기

이 스킬의 문제 신고