Overview
4 min read
In TypeScript, testing means reaching for a third-party framework — Jest, Vitest, Mocha — plus config, a runner, and assertion libraries. Rust bakes testing into the language and Cargo: you annotate a function with #[test], run cargo test, and you are done. This section maps your Jest/Vitest habits onto Rust’s built-in #[test], integration tests in tests/, and documentation tests (your doc examples are compiled and run!), then covers the ecosystem you reach for when the built-ins aren’t enough: mocking with mockall, property-based testing with proptest, benchmarking with criterion, and coverage with cargo-llvm-cov.
What You’ll Learn
Section titled “What You’ll Learn”- How a Jest/Vitest test becomes a
#[test]function inside a#[cfg(test)] mod tests, run withcargo test - The conventions for where tests live — co-located unit tests vs the top-level
tests/directory — and why Rust lets unit tests reach private items - The assertion macros
assert!,assert_eq!,assert_ne!, and how to attach custom failure messages - How to test that code panics with
#[should_panic(expected = "...")], and how to write tests that returnResultso you can use? - How black-box integration tests in
tests/exercise only your public API, and how to share helper code between them - Patterns for setup/teardown without a
beforeEach— helper constructors,LazyLock/once_cellfor shared state, and RAII guards - How to mock dependencies by programming to traits and generating test doubles with mockall (
#[automock]) - How property-based testing with proptest checks invariants across hundreds of generated inputs and shrinks failures to a minimal case
- How to write statistically rigorous benchmarks with criterion (stable), and why the built-in
#[bench]is still nightly-only - How doc tests turn the examples in your
///comments into tests that must keep compiling - How to measure coverage with cargo-llvm-cov and speed up runs with cargo-nextest, plus a practical TDD loop in Rust
Topics
Section titled “Topics”| Topic | Description |
|---|---|
| Unit Tests | Jest/Vitest → #[test] + #[cfg(test)] mod tests, run with cargo test. |
| Test Organization | Where tests live, the tests submodule convention, and testing private vs public items. |
| Assertions | assert!/assert_eq!/assert_ne!, custom messages, and comparing with Debug. |
| Testing Panics | #[should_panic(expected = "...")] and tests that return Result<(), E> so you can use ?. |
| Integration Tests | The tests/ directory: black-box testing of the public API and shared helper modules. |
| Test Fixtures | Setup/teardown patterns: helper constructors, LazyLock/once_cell shared state, and RAII guards. |
| Mocking | Mocking strategies, trait-based test doubles, and mockall’s #[automock]. |
| Property Testing | Property-based testing with proptest: the proptest! macro, shrinking, and vs example-based tests. |
| Benchmarking | Statistically driven benchmarks with criterion, and why #[bench] is nightly-only. |
| Doc Tests | Documentation tests: how /// code blocks run as tests, pub items in scope, and ignore/no_run/should_panic. |
| Coverage | Code coverage with cargo-llvm-cov and faster runs with cargo-nextest. |
| TDD Workflow | A red-green-refactor loop in Rust, with cargo watch for fast feedback. |
Learning Objectives
Section titled “Learning Objectives”By the end of this section, you will be able to:
- Write and run unit tests with
#[test]/cargo test, and decide whether a test belongs co-located or intests/ - Assert with the right macro, write clear failure messages, and test both panics and
Result-returning code - Structure integration tests against your public API and share setup code between them
- Replace
beforeEach/afterEachwith idiomatic fixtures, lazy statics, and RAII cleanup guards - Mock collaborators by depending on traits and generating doubles with mockall
- Cover whole input ranges with proptest, benchmark hot paths with criterion, and keep your documentation honest with doc tests
- Measure coverage, run tests faster with nextest, and drive a feature with a TDD loop
Prerequisites
Section titled “Prerequisites”- Section 12: Modules & Packages — tests live inside the module tree (
#[cfg(test)] mod tests) and in thetests/directory, and the testing crates are added through Cargo, so the module/Cargo model from Section 12 comes first. - Section 08: Error Handling — many tests return
Result<(), E>and use?, and you will assert onOk/Errvalues. - Section 09: Generics & Traits — mocking works by programming to traits, so trait basics make the mocking topic land.
Estimated Time
Section titled “Estimated Time”- Reading: 5 hours
- Hands-on Practice: 4 hours
- Exercises: 2-3 hours
- Total: 10-12 hours
Tip: Start with
unit-tests,assertions, andshould-panic— that trio covers 90% of day-to-day testing. Addintegration-testsanddoc-testsnext. Treatmocking,property-testing,benchmarking, andcoverageas a toolbox to pull from when a specific need arises, rather than something to master up front.
Next: Section 14: Macros → — declarative and procedural macros, Rust’s compile-time code generation.