tests/shop_test.oxl
use super.shop { Payments, Receipt, Declined, pay }
use std.test { clock }
// A fixture: the value before `yield` goes to the test, the code after it is the clean-up.
fixture ledger() -> List<str> {
var entries: List<str> = []
yield entries
print("ledger closed")
}
test "a payment under the limit succeeds" {
assert pay(500) is Receipt
}
test "assert_eq prints both sides on failure" {
assert_eq(2 + 2, 4)
assert_ne("a", "b")
}
test "a payment over the limit is declined" {
assert_fails(pay(200000), Declined)
}
test "fixtures give a fresh value to every test" with ledger as entries {
assert_eq(entries.len(), 0)
}
test "a timeout is retried once" {
mock Payments {
charge(_) => fail Timeout once, then Receipt{ id: 7 }
}
let r = pay(100)
assert r is Receipt
assert_eq(Payments.calls(.charge).count, 2)
}
test "a mock can script an error" {
mock Payments { charge(_) => fail Declined{ why: "fraud" } always }
assert pay(100) is Declined
assert_eq(Payments.calls(.charge).count, 1)
}
// Simulation: the clock is virtual, so an hour costs nothing; the body runs once per seed.
test sim "an hour passes instantly" seeds 1..=5 {
let t0 = now()
clock.advance(1h)
assert now() - t0 == 1h
sleep(30m)
assert now() - t0 == 90m
}Source: examples/testing-demo/tests/shop_test.oxl