F5 · the engine · module 7
Pragmatic testing
The engine from F5.06 was built to be tested. Because decide and
evolve are pure and state is a fold, most of the engine is checked with plain example
tests — arrange a state, call a function, assert the result — with no processes and no mocks. Above
those sit property-based tests that state an invariant and let StreamData
generate hundreds of cases, and contract tests that turn the F5.04 contract into assertions,
with doctests keeping the documentation honest. Pragmatic testing here is largely a dividend of the
architecture: purity is what makes the tests cheap.
Three kinds of test, narrowing as they go. Select a tier to see what it checks and which dive builds it.
One example pins a point; one property covers a region
1 example · 1 input checked
An example test pins a single point in the input space.
A pyramid of tests
Reading the diagram: the base is the pure core — the most tests and the fastest, because
decide and evolve take values and return values. Above it,
fewer property tests assert rules over generated inputs. At the top, contract tests pin the F5.04 guarantees
and doctests verify the examples in the docs. Select a tier.
The testing pyramid · select a tier
tier: Pure core
checks: example tests on decide/evolve
Push the logic into pure functions and the tests follow at low cost: most are arrange, call, assert. The pyramid is wide at the base because that is where purity pays.
Three deep dives
In order: testing the pure core by example; stating properties and letting a generator find the cases; and turning the F5.04 contract into tests that run, with doctests that keep the documentation true.
decide and evolve are pure, so a test is arrange a state, call, assert the output — no process, no mocks.StreamData generate the cases.doctest runs the examples in the docs.F5.06 · the engine
A supervised GenServer whose logic lives in pure decide and evolve, with state as a fold.
F5.07 · test it
Examples on the pure core, properties over generated inputs, and the contract run as tests.
Start with testing the pure core, then property-based testing, then contract tests. The next module, F5.08 — Boundaries & integration seams, wraps the engine behind ports and a facade. The engine under test is F5.06 · where engine state lives.
References
Testing pure functions, generating cases, and running contracts as tests.
Sources
- Elixir — ExUnit — the test framework.
- StreamData — property-based testing.
- Elixir — ExUnit.DocTest — contracts as runnable examples.
Related in this course
- F5.07.1 · Testing the pure core
- F5.07.2 · Property-based testing
- F5.07.3 · Contract tests
- F5.06 · Where engine state lives — the engine under test.
- F5.04 · Design by contract — the contract these tests run.