package windtrap
Install
dune-project
Dependency
Authors
Maintainers
Sources
sha256=2e61a86f8c97502c1f8a593c28e255d591a44b1533c6eed8cd0c847afa3d772a
sha512=060d0a47d926d420e0f96f4912c2690d148d6196bcbb701b2463a4fb9ffade5c4ff4d98d703f4b80b2b8ad1bed848c68f1d613e3ba745f9cd5e7d313e049bdc3
Description
Unit, property, stateful, and expect tests behind one flat API: every assertion failure prints the values and marks what changed, generators shrink integrally and replay from a printed seed, baselines are a literal in the test or a file it names and are accepted with dune promote, and the runner handles filtering, sharding, and JUnit output. Inline expect tests, code coverage, and mutation testing come from the companion ppx_windtrap package.
Tags
testing unit-test property-testing stateful-testing expect-test snapshot-testing coverage mutation-testingAdded to opam-repository:
README
Windtrap — One library for all your OCaml tests
Windtrap runs unit, property, stateful and expect tests from one flat interface, with coverage and mutation testing in the companion ppx. A suite is an ordinary executable that dune runtest builds and runs.
A first suite
open Windtrap
let basics =
group "basics"
[
test "evicts the oldest entry when full" (fun () ->
let c = Lru.create 2 in
List.iter (fun k -> Lru.add c k k) [ 1; 2; 3 ];
equal (option int) None (Lru.find c 1));
test "lists its keys, most recent first" (fun () ->
let c = Lru.create 3 in
List.iter (fun k -> Lru.add c k k) [ 1; 2; 3 ];
ignore (Lru.find c 1);
expect (Lru.to_string c) @@ __POS_OF__ {|1 3 2|});
]
let bounded =
prop "never holds more than its capacity" Gen.(list int) (fun keys ->
let c = Lru.create 3 in
List.iter (fun k -> Lru.add c k k) keys;
at_most int ~than:3 (Lru.size c))
let () = exit (run "lru" [ basics; bounded ])A run with nothing to report prints one line:
$ dune runtest
mylib: 3 passed in 1.0ms (seed s1:b02192cebcec40d2).Features
Unit tests
test and group declare a suite, and run runs it. Assertions such as equal, less, contains, raises and require_some take a witness, for example int or list string, and a failure prints the values it compared.
test "splits on commas" (fun () ->
equal (list string) [ "a"; "b" ] (String.split_on_char ',' "a,b"))Property tests
prop checks a law over values generated with Gen. A failing input is reduced to a smaller one that still fails. Law states textbook laws, such as an involution or a round trip, and a failure names each term.
prop "rev is an involution" Gen.(list int) (Law.involutive (list int) List.rev)Stateful tests
stateful runs generated programs of calls on a system and on a reference, such as a model of its state or another implementation, and compares what each call returns or raises. A failing program is reduced to a shorter one and printed as the calls that ran. With ~domains:2, the middle of each program runs on two domains at once, and the test fails when no order of the calls explains the results.
command "pop" (queue ^-> returns int) Model.pop Bounded_queue.popExpect tests
expect compares a string with a literal in the test's source, and expect_file with a file. ppx_windtrap provides let%expect_test and [%expect]. dune promote accepts a change.
expect (Printf.sprintf "%d items" (List.length cart)) @@ __POS_OF__ {|3 items|}Coverage
ppx_windtrap.coverage instruments a library, and windtrap coverage reports the expressions that the tests did not run.
dune runtest --instrument-with ppx_windtrap.coverage
dune exec windtrap -- coverageMutation testing
ppx_windtrap.mutate compiles mutants of a library, small changes such as >= into >, into its test executables. --mutate runs the tests on each mutant and reports the mutants that no test fails on.
dune exec --instrument-with ppx_windtrap.mutate test/test_calc.exe -- --mutateInstallation
opam install windtrap
opam install ppx_windtrap # expect tests, coverage, mutation testingDocumentation
The manual, doc/manual/, has one page per need:
- Tutorial: Getting started, the suite above and its first failure.
How-to:
- Assertions: values, bounds, strings, results and exceptions.
- Property testing: laws over generated values.
- Stateful testing: a system against a reference.
- Baselines and expect tests:
expect,expect_file,let%expect_test. - Resources and structure: a suite's layout and resources.
- Running tests: selection, reruns,
dune runtestand CI. - Coverage: the code no test runs.
- Mutation testing: the changes no test notices.
- Migrating from 0.1: each 0.1 spelling and its replacement.
- Explanation: Design notes, why windtrap is shaped as it is.
- Reference:
lib/windtrap.mli, andppx/ppx_windtrap.mlifor the inline test forms.
Questions are welcome on the OCaml forum.
Examples
examples/ holds the project of each manual page, run by dune runtest; its README lists them.
Acknowledgments
Windtrap builds on ideas and code from several OCaml projects:
- Alcotest by Thomas Gazagnaire: test structure and runner design.
- Craig Ferguson's Alcotest PRs (#294, #247): API design, subcomponent diffing, and Levenshtein distance (ISC).
- QCheck2 by Simon Cruanes et al.: generator design and integrated shrinking (BSD 2-Clause).
- ppx_expect and ppx_inline_test by Jane Street: expect test paradigm and dune integration.
- Bisect_ppx by Anton Bachin et al.: coverage instrumentation and runtime (MIT).
- mtime by Daniel Bünzli: the monotonic clock (ISC).
THIRD_PARTY_LICENSES.md holds the notices of the code derived from them.