Testing
Mechanoid machines are ordinary ZIO values. Prefer the same scoped start / send style in
unit tests that you use on this site.
Scoped unit tests
Assert outcomes and state after a short path:
{
enum Light derives Finite:
case Red, Green
enum Tick derives Finite:
case Go, Timeout
import Light.*, Tick.*
val machine = Machine(
assembly[Light, Tick](
(Red via Go to Green) @@ Aspect.timeout(1.minute, Timeout),
Green via Timeout to Red,
)
)
ZIO.scoped {
for
fsm <- machine.start(Red)
outcome <- fsm.send(Go)
state <- fsm.currentState
yield (outcome.result.toString, state.toString)
}.asDoc
}(Goto(Green),Green)Negative paths
Illegal events surface as InvalidTransitionError (use .either):
{
enum Light derives Finite:
case Red, Green
enum Tick derives Finite:
case Go, Timeout
import Light.*, Tick.*
val machine = Machine(
assembly[Light, Tick](
(Red via Go to Green) @@ Aspect.timeout(1.minute, Timeout),
Green via Timeout to Red,
)
)
ZIO.scoped {
for
fsm <- machine.start(Red)
failed <- fsm.send(Timeout).either
yield failed
}.asDoc
}Left(InvalidTransitionError(Red,Timeout,No transition defined))Timeouts in tests
| Approach | When |
|---|---|
| Send the timeout event | Deterministic DocSpecs / live clock (this site) |
TestClock.adjust | Fiber timeouts in zio-test without sleeping wall time |
This site uses TestAspect.withLiveClock because EventStore timestamps and producing sleeps need
a real clock; synthetic timeout events keep examples snappy.
{
enum Light derives Finite:
case Red, Green
enum Tick derives Finite:
case Go, Timeout
import Light.*, Tick.*
val machine = Machine(
assembly[Light, Tick](
(Red via Go to Green) @@ Aspect.timeout(1.minute, Timeout),
Green via Timeout to Red,
)
)
ZIO.scoped {
for
fsm <- machine.start(Red)
_ <- fsm.send(Go)
_ <- fsm.send(Timeout)
state <- fsm.currentState
yield state
}.asDoc
}RedLayers and docs-as-tests
Reuse the same InMemoryEventStore / TimeoutStrategy / LockingStrategy layers as the
production ladder pages. Specular DocSpecs are the suite: docs/test and docs/specularSite
fail when an assertion fails. Machines rendered with mermoid parse the Mermaid Mechanoid emits,
so the published picture cannot drift from the graph you run.
See Visualization and the Domains pages.