Suitcase
The structured test toolkit. A lightweight sync Rust library for named cases, optional setup / teardown at suite scope and before_each / after_each around each case. Build case lists with cases!; use test_suite! to emit a single #[test] that runs all cases sequentially with formatted output.
Heavy development: The API is still evolving. Expect breaking changes between releases until a stable 1.0; pin an exact version (or git revision) in Cargo.toml if you need upgrades to be predictable.
Install · Usage · CLI · Assertions · Mocking · Examples · AI-assisted changes · Docs (after publish; cargo doc --open locally)
- Sync runner —
runorchestrates hooks and case bodies; integrate async I/O with something liketokio::runtime::Handle::block_onin hooks or cases. - Sequential execution —
test_suite!emits one#[test]that runs all cases in slice order. Cases that depend on earlier state (setup → mutate → assert) always execute correctly. - Formatted output — Each case prints
▶ name, then✓ name (Xms)or✗ name (Xms). All cases run even if one fails; the first panic is re-raised after completion. - Hooks as optional fns —
HookFnsholdsOption<fn(&mut S)>per lifecycle slot; use [None] to skip. - CLI —
suitecase testrunssuitecase testand renders a formatted summary with pass/fail counts, per-case timing, and failure details. - Assertions —
suitecase::assertprovides testify/assert-style helpers (equal,contains,assert_ok, …) that panic on failure with clear messages (#[track_caller]where applicable). - Mocking —
suitecase::mockprovides testify/mock-style expectations and call recording (Mock,mock_args!). Usesuitecase::mock_argsat the crate root (same macro).
Install
Add suitecase to your Cargo.toml (no required dependencies beyond std):
[]
= "0.1"
Install the CLI:
CLI
Run tests with formatted suitecase output:
Output:
Suitecase Summary
────────────────────────────────────────────────
✓ test_inc (0ms)
✓ test_inc_verify (0ms)
✓ test_double (0ms)
...
────────────────────────────────────────────────
PASSED 12 passed, 0 failed (total: 0ms)
On failure, a FAILURES section shows the panicked case name, duration, file location, and assertion message.
Usage
Quickstart
Put this in tests/suite.rs or #[cfg(test)] mod tests { ... }. The example is suitecase test --example quickstart — one test line that runs every case in order on one suite.
use ;
static MY_CASES: & = cases!;
static MY_HOOKS: = HookFns ;
Run: suitecase test.
Hooks
Pass HookFns as the last argument to run. Each field is Option<fn(&mut S)> — [Some(...)] or [None] / [HookFns::default()].
Sequential test suite (test_suite!)
test_suite! emits a single #[test] that runs all cases sequentially in slice order. Each case prints ▶ name before execution and ✓ name (Xms) or ✗ name (Xms) after. All cases run even if one fails — the first panic is re-raised after all cases complete.
use ;
test_suite!;
Run: suitecase test or suitecase test.
Assertions (assert)
Import helpers from suitecase::assert inside #[test] functions, suite case bodies, or anywhere you want a named check that fails by panicking with a readable message.
use ;
let n = assert_ok;
equal;
contains_str;
See the module docs for the full flat list (collections, errors, floats, options/results, ordering, panics, pointers, time, …).
Mocking (mock)
suitecase::mock is for test doubles: register expectations on a Mock, forward calls from your stub with method_called and mock_args!, then verify with assert_expectations and a small TestingT implementation.
use ;
;
let m = new;
m.on
.returning
.finish;
let out = m.method_called;
assert_eq!;
assert!;
Unexpected calls panic from method_called (see rustdoc). Matchers include eq, anything, anything_of_type, matched_by.
Examples
| Example | Run |
|---|---|
examples/quickstart.rs |
suitecase test --example quickstart · suitecase test --example quickstart |
examples/mock.rs |
cargo run --example mock · suitecase test --example mock (mocked HTTP-style JSON) |
examples/sqlx_sqlite.rs |
suitecase test --example sqlx_sqlite · suitecase test --example sqlx_sqlite |
| Every example at once | suitecase test --examples |
Integration tests (tests/suite.rs) |
suitecase test |
The sqlx example uses sqlx + tokio, embedded migrations in setup_suite, and cases! blocks that call helper functions, plus test_suite!.
[]
= "0.1"
= { = "0.8", = ["runtime-tokio", "sqlite", "migrate"] }
= { = "1", = ["macros", "rt-multi-thread"] }
More documentation
AI_USAGE.md— using LLMs to draft changes is allowed; you must understand the patch, justify it in review, and avoid unnecessary complexity (see file).cargo doc --open—cases!andtest_suite!include declaration / description / examples.- Crate root and
suitedescribe howrunselects cases and orders hooks. assert— panicking assertion helpers (submodules per domain; flat re-exports at the module root).mock—Mock, matchers,Arguments,mock_args!.