Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/mirage/alcotest
A lightweight and colourful test framework
https://github.com/mirage/alcotest
ocaml unit-testing
Last synced: 22 days ago
JSON representation
A lightweight and colourful test framework
- Host: GitHub
- URL: https://github.com/mirage/alcotest
- Owner: mirage
- License: isc
- Created: 2013-12-12T16:58:41.000Z (almost 11 years ago)
- Default Branch: main
- Last Pushed: 2024-09-23T15:43:53.000Z (about 1 month ago)
- Last Synced: 2024-09-29T06:41:09.121Z (about 1 month ago)
- Topics: ocaml, unit-testing
- Language: OCaml
- Size: 3.75 MB
- Stars: 450
- Watchers: 24
- Forks: 80
- Open Issues: 48
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGES.md
- Contributing: CONTRIBUTING.md
- License: LICENSE.md
Awesome Lists containing this project
- awesome-luooooob - mirage/alcotest - A lightweight and colourful test framework (OCaml)
- awesome-list - alcotest
README
A lightweight and colourful test framework.
Alcotest exposes a simple interface to perform unit tests. It exposes
a simple `TESTABLE` module type, a `check` function to assert test
predicates and a `run` function to perform a list of `unit -> unit`
test callbacks.Alcotest provides a quiet and colorful output where only faulty runs
are fully displayed at the end of the run (with the full logs ready to
inspect), with a simple (yet expressive) query language to select the
tests to run. See [the manpage](./alcotest-help.txt) for details.The API documentation can be found [here][docs]. For information on
contributing to Alcotest, see [CONTRIBUTING.md](./CONTRIBUTING.md).[![OCaml-CI Build Status](https://img.shields.io/endpoint?url=https://ci.ocamllabs.io/badge/mirage/alcotest/main&logo=ocaml)](https://ci.ocamllabs.io/github/mirage/alcotest)
[![Alcotest Documentation](https://img.shields.io/badge/doc-online-blue.svg)][docs][docs]: https://mirage.github.io/alcotest/alcotest/Alcotest/index.html
### Examples
A simple example (taken from `examples/simple.ml`):
Generated by the following test suite specification:
```ocaml
(* Build with `ocamlbuild -pkg alcotest simple.byte` *)(* A module with functions to test *)
module To_test = struct
let lowercase = String.lowercase_ascii
let capitalize = String.capitalize_ascii
let str_concat = String.concat ""
let list_concat = List.append
end(* The tests *)
let test_lowercase () =
Alcotest.(check string) "same string" "hello!" (To_test.lowercase "hELLO!")let test_capitalize () =
Alcotest.(check string) "same string" "World." (To_test.capitalize "world.")let test_str_concat () =
Alcotest.(check string) "same string" "foobar" (To_test.str_concat ["foo"; "bar"])let test_list_concat () =
Alcotest.(check (list int)) "same lists" [1; 2; 3] (To_test.list_concat [1] [2; 3])(* Run it *)
let () =
let open Alcotest in
run "Utils" [
"string-case", [
test_case "Lower case" `Quick test_lowercase;
test_case "Capitalization" `Quick test_capitalize;
];
"string-concat", [ test_case "String mashing" `Quick test_str_concat ];
"list-concat", [ test_case "List mashing" `Slow test_list_concat ];
]
```The result is a self-contained binary which displays the test
results. Use `dune exec examples/simple.exe -- --help` to see the
runtime options.Here's an example of a of failing test suite:
By default, only the first failing test log is printed to the console
(and all test logs are captured on disk). Pass `--show-errors` to
print all error messages.### Using Alcotest with opam and Dune
Add `(alcotest :with-test)` to the `depends` stanza of your
`dune-project` file, or `"alcotest" {with-test}` to your opam file.
Use the `with-test` [package variable][with-test] to declare your
tests opam dependencies. Call opam to install them:```sh-session
$ opam install --deps-only --with-test .
```You can then [declare your test][tests] and link with Alcotest: `(test
(libraries alcotest …) …)`, and run your tests:```sh-session
$ dune runtest
```[with-test]: https://opam.ocaml.org/doc/Manual.html#pkgvar-with-test
[tests]: https://dune.readthedocs.io/en/stable/tests.html#custom-tests### Selecting tests to execute
You can filter which tests to run by supplying a regular expression
matching the names of the tests to execute, or by passing a regular
expression _and_ a comma-separated list of test numbers (or ranges of
test numbers, e.g. `2,4..9`):```sh-session
$ ./simple.native test '.*concat*'
Testing Utils.
[SKIP] string-case 0 Lower case.
[SKIP] string-case 1 Capitalization.
[OK] string-concat 0 String mashing.
[OK] list-concat 0 List mashing.
The full test results are available in `_build/_tests`.
Test Successful in 0.000s. 2 tests run.$ ./simple.native test 'string-case' '1..3'
Testing Utils.
[SKIP] string-case 0 Lower case.
[OK] string-case 1 Capitalization.
[SKIP] string-concat 0 String mashing.
[SKIP] list-concat 0 List mashing.
The full test results are available in `_build/_tests`.
Test Successful in 0.000s. 1 test run.
```Note that you cannot filter by test case name (i.e. `Lower case` or
`Capitalization`), you must filter by test name & number instead.See the [examples][] directory for more examples.
[examples]: https://github.com/mirage/alcotest/tree/main/examples
### Quick and Slow tests
In general you should use `` `Quick`` tests: tests that are ran on any
invocations of the test suite. You should only use `` `Slow`` tests
for stress tests that are ran only on occasion (typically before a
release or after a major change). These slow tests can be suppressed
by passing the `-q` flag on the command line, e.g.:```sh-session
$ ./test.exe -q # run only the quick tests
$ ./test.exe # run quick and slow tests
```### Passing custom options to the tests
In most cases, the base tests are `unit -> unit` functions. However,
it is also possible to pass an extra option to all the test functions
by using `'a -> unit`, where `'a` is the type of the extra parameter.In order to do this, you need to specify how this extra parameter is
read on the command-line, by providing a [Cmdliner term][] for
command-line arguments which explains how to parse and serialize
values of type `'a` (*note:* do not use positional arguments, only
optional arguments are supported).[Cmdliner term]: https://erratique.ch/software/cmdliner/doc/Cmdliner/Term/index.html
For instance:
```ocaml
let test_nice i = Alcotest.(check int) "Is it a nice integer?" i 42let int =
let doc = "What is your preferred number?" in
Cmdliner.Arg.(required & opt (some int) None & info ["n"] ~doc ~docv:"NUM")let () =
Alcotest.run_with_args "foo" int [
"all", ["nice", `Quick, test_nice]
]
```Will generate `test.exe` such that:
```sh-session
$ test.exe test
test.exe: required option -n is missing$ test.exe test -n 42
Testing foo.
[OK] all 0 int.
```### Lwt
Alcotest provides an `Alcotest_lwt` module that you could use to wrap
Lwt test cases. The basic idea is that instead of providing a test
function in the form `unit -> unit`, you provide one with the type
`unit -> unit Lwt.t` and alcotest-lwt calls `Lwt_main.run` for you.However, there are a couple of extra features:
- If an async exception occurs, it will cancel your test case for you
and fail it (rather than exiting the process).- You get given a switch, which will be turned off when the test case
finishes (or fails). You can use that to free up any resources.For instance:
```ocaml
let free () = print_endline "freeing all resources"; Lwt.return ()let test_lwt switch () =
Lwt_switch.add_hook (Some switch) free;
Lwt.async (fun () -> failwith "All is broken");
Lwt_unix.sleep 10.let () =
Lwt_main.run @@ Alcotest_lwt.run "foo" [
"all", [
Alcotest_lwt.test_case "one" `Quick test_lwt
]
]
```Will generate:
```sh-session
$ test.exe
Testing foo.
[ERROR] all 0 one.
-- all.000 [one.] Failed --
in _build/_tests/all.000.output:
freeing all resources
[failure] All is broken
```### Comparison with other testing frameworks
The README is pretty clear about that:
> Alcotest is a lightweight and colourful test framework.
Alcotest is the only testing framework using colors!
More seriously, Alcotest is similar to [ounit][] but it fixes a few of
the problems found in that library:- Alcotest has a nicer output, it is easier to see what failed and
what succeeded and to read the log outputs of the failed tests;- Alcotest uses combinators to define pretty-printers and comparators
between the things to test.Other nice tools doing different kind of testing also exist:
- [qcheck][] does random generation and property testing (e.g. Quick
Check);- [crowbar][] and [bun][] are similar to qcheck, but use
compiler-directed randomness, i.e. they take advantage of the AFL
support the OCaml compiler;- [ppx_inline_tests][] allows to write tests in the same file as
your source-code; they will be run only in a special mode of
compilation.[ounit]: https://github.com/gildor478/ounit
[qcheck]: https://github.com/c-cube/qcheck
[crowbar]: https://github.com/stedolan/crowbar
[bun]: https://github.com/yomimono/ocaml-bun
[ppx_inline_tests]: https://github.com/janestreet/ppx_inline_test