Tests
A test is a declaration test "name" { … } next to the code or in the tests/ directory. oxl test builds and runs them in
parallel (§18.1). Assertions: assert cond, assert_eq(a, b) / assert_ne (print both sides),
assert_fails(expression, ErrorType), assert_snapshot.
fn clamp(x: i32, lo: i32, hi: i32) -> i32 pure => if x < lo { lo } else if x > hi { hi } else { x }
test "clamp keeps values inside the range" {
assert_eq(clamp(5, 0, 10), 5)
assert_eq(clamp(-3, 0, 10), 0)
assert_eq(clamp(99, 0, 10), 10)
}
fixture numbers() -> List<i32> {
yield [1, 2, 3]
}
test "fixtures give a value to the test" with numbers as xs {
assert_eq(xs.len(), 3)
}Replacing services: mock#
mock S { method(patterns) => answer … } replaces a service for the duration of a test; answers are given in order (once,
times n, always), fail … returns an error, and S.calls(.method) records the calls with their arguments and context
(§18.3).
@error data Declined { reason: str }
data Receipt { id: i64 }
service Payments {
@public rpc charge(amount: i64) -> Receipt | Declined
}
impl Payments {
rpc charge(amount) { Receipt{ id: 0 } }
}
test "fail once, then the last response repeats" {
mock Payments {
charge(_) => fail Timeout once, then Receipt{ id: 1 }
}
assert Payments.charge(10) is Timeout
assert Payments.charge(10) is Receipt
assert Payments.charge(10) is Receipt
assert_eq(Payments.calls(.charge).count, 3)
}Kinds of tests#
| Declaration | What it is | Run with |
|---|---|---|
test "…" | unit test, one node in the process | oxl test |
test integ "…" with cluster(nodes: 3) | a real cluster of processes | oxl test --kind integ |
test sim "…" seeds 1..=300 | deterministic simulation: virtual clock and network, node crashes, one run per seed | oxl test --kind sim, --seed 7 replays one seed |
test ab "…", bench, fuzz, contract | A/B experiments, benchmarks, fuzzing, schema checks | --kind ab… |
A simulation is reproducible: the result depends only on the seed, and a failing seed is printed with the command to replay it. The clock is virtual, so an hour passes instantly (§18.4):
use std.test { clock }
use std.time { sleep, now }
test sim "an hour passes instantly" seeds 1..=3 {
let t0 = now()
clock.advance(1h)
assert now() - t0 == 1h
sleep(30m)
assert now() - t0 == 90m
}The complete project with all kinds is testing-demo; simulation, network faults and node crashes are in the
guide. Filters: -f regex, --exact, -t tag, --failed, --changed; coverage: --coverage
(oxl test).