Testing: courses and links¶
Level: reference · the reading list
One line: The sources behind this section, starting with the one course that goes past #[test]: what it teaches section by section, which pages here cover the same ground with programs that ran, and the places where the course has fallen behind the tools.
All links checked 2026-09-16. Crate versions are from crates.io on the same day.
Advanced Rust testing¶
Advanced Rust testing ↗ by Luca Palmieri (Mainmatter ↗), the author of 100 Exercises to Learn Rust and Zero To Production. It is a one-day classroom workshop that also works alone. The book is short, and most of the teaching is in the exercises: each section is a Cargo package in the companion repository ↗, and answers are on its solutions branch ↗.
Before you start: you need stable and nightly toolchains, a clone of the repository, and wr, the workshop runner ↗, which checks each exercise before letting you move on. Since the subject is tests, an exercise is checked by how your tests fail: a small tool runs them and compares the outcome with an expectations.yml beside the exercise, which you are told never to edit. The database section also needs Docker.
Who it is for: someone who already writes #[test] and assert_eq! without thinking, and now has code that talks to a filesystem, a database or an HTTP API. If that is not you yet, start with What a test asserts and Where a test goes.
The repository has no licence file, so this library links to the course rather than copying from it. The pages in the right-hand column below are written from scratch, and each is backed by its own program.
Section by section¶
| Course section | What it teaches | Crate | Here |
|---|---|---|---|
| Better assertions ↗ | why a shared assertion library beats home-made helpers; googletest matchers for Option, Result, enums and collections; writing a Matcher; expect_that!, which records a failure and carries on so one test reports every broken property |
googletest ↗ 0.14.3 |
What a test asserts |
| Snapshot testing ↗ | insta: save an output, review changes with cargo insta review, inline or file snapshots, redactions for timestamps and random ids |
insta ↗ 1.48.0 |
every lesson here is one: see below |
| Mocks ↗ | refactor to an interface first; #[automock], times, Sequence, checkpoint; mock! for traits from other crates; why mock-heavy suites get expensive to maintain |
mockall ↗ 0.15.0 |
A test double is a second impl |
| The testing system ↗ | which tests are compiled into which binary, and what tests in one process share | — | How cargo test runs your tests |
| Filesystem isolation ↗ | take paths as arguments; NamedTempFile, tempfile(), TempDir; paths relative to a root rather than the working directory |
tempfile ↗ 3.27.0 |
Temporary directories in tests |
| Database isolation ↗ | in-memory stand-ins, rolled-back transactions, or a logical database per test, and why the third wins; #[sqlx::test] |
sqlx ↗ 0.9.0 |
not covered yet |
| HTTP mocking ↗ | take base URLs as arguments; MockServer on a random port, matchers, expectations, scoped mocks |
wiremock ↗ 0.6.5 |
Injecting the base URL and Mocking a server, both outlines so far |
| Macros ↗ | what #[tokio::test] expands to; an attribute macro that adds #[test] and before/after hooks, with syn and quote |
syn, quote |
What an attribute is; the expansion of #[test] in A harness of your own |
| Test harnesses ↗ | [[test]] with harness = false; libtest-mimic |
libtest-mimic ↗ 0.8.2 |
A harness of your own |
| Capstone ↗ | a harness that starts one Postgres container, gives every test its own database, and runs them in parallel | all of the above | — |
Snapshot testing is how this whole library is checked. Every examples/*.rs has a recorded .out beside it, CI fails when the program's output drifts from it, and run_examples.py --update --only <stem> accepts a change after you have read it. That is insta's review loop, applied to programs instead of values, and CONTRIBUTING is its manual. The course's advice about redactions is this library's determinism rule seen from the other side: where insta removes the timestamp from a snapshot, an example here never prints one.
Read with care¶
Each item was checked on 2026-09-16 against Rust 1.98.0 or against the crate's current documentation. The course is right about the ideas in every case; these are the details that have moved.
- The
assert_eq!failure message in The built-in toolkit is the older format, with backticks round(left == right)and each value. Rust 1.98.0 printsassertion `left == right` failedand thenleft: 1andright: 2on their own lines, unquoted. The course's claim about custom messages is still right:assert!'s message replaces the default, whileassert_eq!'s is appended afterfailed:and the values still print. What a test asserts shows the current output. - Unit tests get one binary per target, not per package. The testing system says a package's unit tests share one binary. A package with
src/lib.rs,src/main.rsandsrc/bin/report.rsproduced three unit-test binaries. - Doc tests are merged on edition 2024. The testing system says each doc test is compiled into a binary of its own, which is true only before edition 2024. On 2024, rustdoc compiles a crate's doc tests into one merged binary (
merged doctests compilation took 0.38s). Each doc test still runs in a process of its own; two that wrote their process id wrote different ids. - A directory under
tests/is a test target only when it holdsmain.rs. The testing system counts a directory such astests/foo/as a target by itself.tests/common/mod.rsalone produces no binary, which is why shared helpers go there. - A custom harness may fail with any non-zero exit status, where Quaking like
cargo testsays it must be exactly 1. Any non-zero status is a failure, and cargo exits with the harness's status: amainthat exited 3 madecargo testexit 3. libtest itself uses 101. assert_display_snapshot!, listed amonginsta's macros, is deprecated in 1.48.0, and its docs say to useassert_snapshot!instead.#[sqlx::test]deletes the test database only when the test passes. Testing withsqlxlists deletion as the last step, unconditionally. The 0.9.0 docs say failed tests leave their databases in place for debugging, and the next run of a test binary deletes them.MockServer::register_scoped, named in the HTTP section's Checkpoints, isregister_as_scopedinwiremock0.6.5. The same page's bullet list has the right name.- Documentation links are pinned to old versions:
googletest0.11.0 (now 0.14.3),mockall0.12.1 (now 0.15.0),sqlx0.7.3 (now 0.9.0). Read the current docs before copying a trait signature. - Nothing promises to empty the temporary directory. Temporary files says the OS deletes files there eventually;
std::env::temp_dir↗ makes no such promise. It warns instead that the directory may be shared with other users and that predictable file names are a security problem.tempfile's own cleanup is what to rely on.
Official documentation¶
- The Book, ch. 11 — Writing automated tests ↗:
#[test],assert!,should_panic, and test organisation ↗, which answers "unit or integration, and which file". - The rustc book — Tests ↗: libtest's command line in full:
--exact,--list,--ignored,--test-threads,--nocapture, and the unstable ones. - The Cargo book —
cargo test↗ and target settings ↗:--no-fail-fast, test target discovery, and theharnessfield. - The rustdoc book — Documentation tests ↗: fence attributes, hidden lines, and how doc tests are merged in edition 2024.
Tools, by the question they answer¶
| If the question is… | Reach for | Here |
|---|---|---|
| can one test process crash the rest? | cargo-nextest ↗: one process per test | cargo-nextest |
| did the output change, and was that intended? | insta ↗ |
the snapshot note above |
| does this hold for inputs I did not think of? | proptest ↗: generated inputs, shrunk to the smallest failing case | — |
| does anything crash on hostile input? | cargo-fuzz ↗ | — |
| the same test, many rows, each reported separately | rstest ↗ cases and fixtures |
A harness of your own, practice |
| does this code fail to compile, with the right error? | trybuild ↗ |
— |
which part of a long assert_eq! differs? |
pretty_assertions ↗: a coloured diff |
— |
The property, snapshot, compile-fail and fuzz rows are what Other kinds of test is being written to cover, one example each.
Books¶
- Zero To Production In Rust ↗ (paid), by the course's author. Its testing chapters build the same approach inside a real service: a database per test,
wiremockfor the email provider, black-box tests through HTTP. The books shelf has the full verdict. - 100 Exercises to Learn Rust ↗, the same author's free course, is test-driven from the first exercise. It is the one to do before this one; see Exercises.
Po polsku¶
Kurs Advanced Rust testing nie ma polskiej wersji, ale jest krótki i w większości składa się z ćwiczeń, więc angielskiego do przeczytania jest niewiele. Znacznie więcej jest do napisania. Warto zacząć od sekcji The testing system (czyli od strony Co buduje cargo test), bo tłumaczy, dlaczego testy w jednym pliku wykonywalnym dzielą katalog roboczy i zmienne static, a wszystkie późniejsze sekcje o izolacji plików, baz danych i HTTP są odpowiedzią właśnie na to. Lista „Read with care” powyżej zbiera miejsca, w których kurs rozminął się z Rustem 1.98 albo z aktualnymi wersjami bibliotek: format komunikatu assert_eq!, scalone w edycji 2024 testy dokumentacyjne, przestarzałe assert_display_snapshot! i #[sqlx::test], które po nieudanym teście zostawia bazę do obejrzenia. Idee są wszędzie trafne; zmieniły się szczegóły.
Szukaj po polsku: testowanie w Ruście · testy migawkowe (snapshot testing) · atrapy i mocki · izolacja testów · rust advanced testing workshop · rust googletest insta mockall wiremock