mock
Test mocking and stubbing - create stub functions that return a fixed value or delegate to a function, wrap any function in a spy that records every call, replace object fields temporarily with restore support, inspect call counts and arguments, return a sequence of values across calls, throw on call, and collect fakes into a test module for bulk verification.
Load with: use mock
What this module does
mock gives you the classic test-double toolkit. Stubs replace
real functions with controlled return values. Spies wrap real functions and
record calls without changing behaviour. Object stubs (mocst)
replace a field on an object and give you a restore handle. The test module
(moctm) collects named fakes and can verify all of them were
called at least once.
Quick example
use mock
# Stub - always returns "ok"
m = mock.fn("ok")
prn(m.fn("anything")) # "ok"
# Computed stub
m2 = mock.fn(\(x) x * 2)
prn(m2.fn(5)) # 10
# Spy - records calls, delegates to original
real = \(x) x + 1
sp = mock.spy(real)
sp.fn(10)
sp.fn(20)
prn(mock.count(sp)) # 2
prn(mock.last(sp)) # 20
prn(mock.with(sp, 10)) # tru
# Stub object field
db = {query: \(q) "real result"}
s = mock.stub(db, "query", \(q) "mocked")
prn(db.query("SELECT 1")) # "mocked"
db = mock.rst(s) # restore original
prn(db.query("SELECT 1")) # "real result"
# Sequential return values
seq = mock.seq(["first", "second", "third"])
prn(seq.fn(nil)) # "first"
prn(seq.fn(nil)) # "second"
prn(seq.fn(nil)) # "third" (repeats last)
# Error mock
em = mock.err("not implemented")
try(\() em.fn(nil)) # throws "not implemented"
# Test module with verify
tm = mock.tm()
mock.fake(tm, "save", \(x) tru)
# ... call save ...
mock.verify(tm) # throws if any fake was never called
Functions
Creating mocks
mocfn(rv) / mock.fn(rv)Creates a stub. If rv is a function it is called with the argument; otherwise rv is returned directly. Returns {fn, calls}.
mocsp(orig) / mock.spy(orig)Creates a spy wrapping orig. Calls are forwarded to orig and recorded. Returns {fn, calls, orig}.
mocse(rets) / mock.seq(rets)Creates a stub that returns values from rets in sequence. Repeats the last value once the list is exhausted.
mocer(msg) / mock.err(msg)Creates a stub that always throws msg when called.
Object stubbing
mocst(obj, key, val) / mock.stub(obj, key, val)Replaces obj[key] with val and returns a stub handle {obj, key, orig}.
mocrst(stub) / mock.rst(stub)Restores the original value and returns the updated object.
Assertions
moccn(m) / mock.count(m)Returns the number of recorded calls.
mocca(m) / mock.any(m)Returns tru if the mock was called at least once.
mocnc(m, n) / mock.n(m, n)Returns tru if the mock was called exactly n times.
moccw(m, args) / mock.with(m, args)Returns tru if the mock was ever called with args.
moclc(m) / mock.last(m)Returns the argument from the most recent call, or nil.
mocfc(m) / mock.first(m)Returns the argument from the first call, or nil.
mocrr(m) / mock.clr(m)Returns a copy of the mock with the call history cleared.
Test module
moctm() / mock.tm()Creates a test module registry {fakes}.
mocfk(tm, name, rv) / mock.fake(tm, name, rv)Registers a named fake in the test module. Returns the fake's .fn.
mocgt(tm, name) / mock.get(tm, name)Retrieves a registered fake by name.
mocva(tm) / mock.verify(tm)Throws an error naming the first fake that was never called. Returns tru if all fakes were called.
Notes
- Requires
trl.