Skip to main content

Testing, Fixtures, and Code Review Culture

Watch First

Why This Matters

Rust code that compiles can still be wrong. Tests, fixtures, and review habits create the confidence to refactor without guessing.

The goal is not maximum test count. The goal is useful feedback at the right boundary.

What You Will Build

Add unit, integration, HTTP, and DB-backed tests to the task API. Review an AI-generated patch and improve it before merging.

Concept

Use a testing pyramid that matches risk:

Fast domain tests should catch most logic mistakes. HTTP and database tests should prove boundaries, not repeat every unit test.

Rust Pattern

Keep tests close to behavior:

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

#[test]
fn assigned_task_can_be_completed() {
let status = transition(TaskStatus::Assigned, TaskStatus::Completed);
assert_eq!(status, Ok(TaskStatus::Completed));
}

#[test]
fn draft_task_cannot_be_completed() {
let status = transition(TaskStatus::Draft, TaskStatus::Completed);
assert!(matches!(
status,
Err(TaskError::InvalidTransition { .. })
));
}
}

Practice

Keep this mistake out of your first implementation.

Avoid tests that only prove mocks were called. Prefer behavior that matters:

Weak: repository.save was called once
Better: completing a task stores completed status and emits a completion event

Keep these concrete mistakes out of your work.

  • Writing tests that compile but do not assert meaningful behavior.
  • Mocking every dependency instead of using small fakes.
  • Skipping error cases.
  • Ignoring database migrations and SQL behavior.
  • Adding benchmarks before correctness is established.

Use this sequence. Do not move to the next row until you have produced the artifact in the right column.

StepFocusArtifact
Rust testing pyramidUnit, integration, HTTP, DB, property testsTest strategy note
Domain testsState transitions, validation, permissions, errorsDomain test suite
Axum handler testsTest app state, request, status, JSONHTTP tests
Database testsMigrations, fixtures, isolated DBs or transactionsSQL behavior tests
Fakes vs mocksMeaningful capability fakesFake repository
Documentation testsExecutable public API examplesDoctest
BenchmarksMeasure meaningful paths after correctnessOptional benchmark
Review checklistHuman review as engineering habitPatch review note

Build this now. Keep each change small enough that you can run cargo check, cargo test, and inspect the diff.

Add tests for:

  • valid task creation,
  • invalid empty title,
  • invalid state transition,
  • unauthorized update,
  • list pagination,
  • repository query for missing record.

Then refactor one function and prove the tests still pass.

After your own attempt, use another reviewer or an AI tool as a second pass. Accept a suggestion only when you can explain why it preserves the lesson design.

Ask AI to add tests for the service. Review whether:

  • tests fail for the right reason before the fix,
  • both success and error paths are covered,
  • fakes are simpler than mocks,
  • fixtures are readable,
  • database tests verify SQL behavior.

You can move on when these statements are true.

  • Does it compile?
  • Does it have tests at the right boundary?
  • Are errors typed where they matter?
  • Are clones intentional?
  • Is async used only where needed?
  • Are locks scoped narrowly?
  • Is the abstraction simpler than the duplication?
  • Would another engineer understand this in six months?

Curated Resources

Next Step

Continue to Security, Authentication, and API Safety.