Skip to content

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.

  1. 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 prints assertion `left == right` failed and then left: 1 and right: 2 on their own lines, unquoted. The course's claim about custom messages is still right: assert!'s message replaces the default, while assert_eq!'s is appended after failed: and the values still print. What a test asserts shows the current output.
  2. 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.rs and src/bin/report.rs produced three unit-test binaries.
  3. 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.
  4. A directory under tests/ is a test target only when it holds main.rs. The testing system counts a directory such as tests/foo/ as a target by itself. tests/common/mod.rs alone produces no binary, which is why shared helpers go there.
  5. A custom harness may fail with any non-zero exit status, where Quaking like cargo test says it must be exactly 1. Any non-zero status is a failure, and cargo exits with the harness's status: a main that exited 3 made cargo test exit 3. libtest itself uses 101.
  6. assert_display_snapshot!, listed among insta's macros, is deprecated in 1.48.0, and its docs say to use assert_snapshot! instead.
  7. #[sqlx::test] deletes the test database only when the test passes. Testing with sqlx lists 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.
  8. MockServer::register_scoped, named in the HTTP section's Checkpoints, is register_as_scoped in wiremock 0.6.5. The same page's bullet list has the right name.
  9. Documentation links are pinned to old versions: googletest 0.11.0 (now 0.14.3), mockall 0.12.1 (now 0.15.0), sqlx 0.7.3 (now 0.9.0). Read the current docs before copying a trait signature.
  10. 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

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, wiremock for 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