Unit Testing
Rank ships with a lightweight, deterministic test runner through rank test. Use it when you want to pin either the evaluated output or the expected diagnostics for a program without building a separate host harness.
What rank test is for
Use rank test when you need:
- repeatable output checks for pure programs
- deterministic fixtures for
Env<T> {}andHTTP::Fetch<T> {} - local or stubbed provider behavior instead of live backends
- regression coverage for diagnostics as well as success output
- machine-readable suite reports for CI
The command accepts either one case directory or a suite root that contains many case directories:
rank test examples/tests
rank test examples/tests/yaml-expected
rank test examples/tests --filter provider
rank test examples/tests --format json
Test case layout
Each case directory is driven by a rank-test.json manifest.
Minimal value-output case:
my-case/
rank-test.json
expected.json
src/
main.rank
Minimal manifest:
{
"kind": "rank/test-case",
"version": 1,
"entry": "src/main.rank",
"expectedValue": "expected.json"
}
expectedValue may point to JSON or YAML. Use JSON when you want the least ambiguity in scalar values and YAML when you want the fixture to read like normal Rank output.
Output assertions
For ordinary values, the expected file contains the realized document value.
Example expected JSON:
{
"service": {
"host": "localhost",
"port": 443
}
}
If pub main returns Emit::manifest(...), the expected value should be the descriptor envelope, not the materialized filesystem tree:
{
"kind": "rank/output-manifest",
"version": 1,
"entries": [
{
"path": "README.md",
"format": "text",
"value": "# api\n"
}
]
}
Diagnostic assertions
Tests can also pin expected diagnostics instead of an output value.
Example manifest:
{
"kind": "rank/test-case",
"version": 1,
"entry": "src/main.rank",
"expectedDiagnostics": [
{
"code": "TYP007",
"messageContains": "Field missing does not exist"
}
]
}
Use exact message only when the full text is intentionally stable. Prefer messageContains for diagnostics that include long rendered type shapes or paths.
Deterministic external inputs
Case directories may include fixture files for external inputs:
env.jsonforEnv<T> {}readshttp.jsonforHTTP::Fetch<T> {}snapshotsprovider-stubs.jsonfor backend provider outputs keyed by public export name and exact full input- a local
rank.tomlplusproviders/directory when you want to exercise a path-based provider package directly
This keeps the suite reproducible even when the production program normally depends on host state or remote services.
Backend provider stubs
provider-stubs.json is a small object keyed by public provider export name:
{
"api::users::lookup": [
{
"input": {
"id": "123",
"cacheKey": "lookup-123"
},
"output": {
"name": "stubbed-user-123"
}
}
]
}
Each entry matches the backend provider call by exact full input. If a backend invocation has no matching stub, rank test fails instead of falling through to a live runtime call.
Running suites in CI
Text output is good for local iteration:
rank test examples/tests
Structured reports are better for automation:
rank test examples/tests --format json
rank test examples/tests --format yaml
--filter <pattern> is useful when narrowing one failing slice inside a larger suite.
Where to look next
- The sample cases under examples/test-fixtures show several supported workflows.
- The command-line flags are listed in CLI Reference.
- For runtime debugging outside the test harness, see Debugging.