jonnifyelixir
F5 · Pragmatic Programming / F5.07 · testing

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

INPUT SPACE OF evolve(state, event) invariant: progress in 0..100 one chosen case

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

CONTRACTS pre / post / invariant + doctests PROPERTIES invariants over generated inputs PURE CORE decide / evolve — fast, no setup

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.

F5.07.1
Testing the pure core
decide and evolve are pure, so a test is arrange a state, call, assert the output — no process, no mocks.
F5.07.2
Property-based testing
State a rule true for all valid inputs — replay is deterministic, progress stays in 0..100 — and let StreamData generate the cases.
F5.07.3
Contract tests
The F5.04 precondition, postcondition, and invariant become assertions, and 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

Related in this course