-
Notifications
You must be signed in to change notification settings - Fork 29
Description
(After writing this up, I noticed something similar-sounding in the TODO, which is probably a good sign. I'm sending this anyway, to add support for the idea, to flesh out the design a bit, and to open up discussion.)
At present the interface to tests is quite stateful: there's a function for adding tests to a global list
val add_test : ?name:string -> ('f, test_result) gens -> 'f -> unitand the tests are implicitly invoked by a function installed with at_exit.
This interface makes it a little difficult to integrate crowbar into larger test frameworks.
It would be helpful to have an ounit/alcotest-style interface, where the user constructs test suites, perhaps hierarchically, and where invoking the tests is the user's responsibility.
For example, here's a basic less-stateful interface that sticks quite closely to the spirit of the current design:
type test
val test : ?name:string -> ('f, test_result) gens -> 'f -> test
val run_main : test list -> unitWith an interface like this one might write:
let tests = [
Crowbar.test "some property"
test_some_property [int; string] @@ fun i s ->
(* ... *)
;
Crowbar.test "another property"
test_another_property [list1 string] @@ fun ss ->
(* ... *)
;
]
let () = run_main testsCrucially, since this interface separates the operations of defining tests and registering/invoking them, it's easier to select tests (or even decide whether or not to invoke the crowbar-based testsuite at all) based on command-line options or other input.
Is there some reason why it'd be tricky to add such an interface? I wonder if the current approach with atexit is just for convenience, or if there's some deeper technical reason why it's better to do things that way.