Alcotest

repository·main·Indexed 19 days ago

https://github.com/mirage/alcotest

A lightweight, colorful, and expressive unit testing framework for OCaml. It supports synchronous and asynchronous (Lwt) testing, provides clean output, and allows for easy test selection via regex and index numbers. Key features include support for 'Quick' and 'Slow' test speeds, JSON output for scripting, and integration with Dune and opam.

Tokens
2.7K
Snippets
10
Records
16
Agent score
67%

What's inside alcotest

  1. Use Quick and Slow tests

    main

    Alcotest supports two test speeds to help manage execution time:

    • `Quick: Standard tests intended to run on every invocation.
    • `Slow: Stress tests or heavy computations intended to run occasionally (e.g., before a release).

    To suppress `Slow tests and run only `Quick tests, use the -q flag.

    $ ./test.exe -q # run only the quick tests
    $ ./test.exe    # run quick and slow tests
  2. Basic usage of Alcotest

    main

    Alcotest provides a simple interface for unit testing using check for assertions and run to execute a suite of tests. Tests are organized into a hierarchy of suites and test cases.

    Key components:

    • Alcotest.(check type) "message" expected actual: Asserts that actual matches expected using the provided type's comparator.
    • test_case "name" speed test_function: Creates a test case with a name and a speed (Quick or Slow).
    • run "suite_name" [ ... ]: Executes the test suite.

    Commonly used types for check include string, int, and list int.

    module To_test = struct
      let lowercase = String.lowercase_ascii
      let list_concat = List.append
    end
    
    let test_lowercase () =
      Alcotest.(check string) "same string" "hello!" (To_test.lowercase "hELLO!")
    
    let test_list_concat () =
      Alcotest.(check (list int)) "same lists" [1; 2; 3] (To_test.list_concat [1] [2; 3])
    
    let () =
      let open Alcotest in
      run "Utils" [
          "string-case", [
              test_case "Lower case"     `Quick test_lowercase;
            ];
          "list-concat",   [ test_case "List mashing"   `Slow  test_list_concat ];
        ]
  3. Install Alcotest with opam and Dune

    main

    To use Alcotest in an OCaml project:

    1. Opam configuration: Add (alcotest :with-test) to your dune-project file or "alcotest" {with-test} to your .opam file. Use the with-test package variable to ensure it is only a dependency during testing.
    2. Installation: Run opam install --deps-only --with-test . to install dependencies.
    3. Dune configuration: In your dune file, declare the test dependency using (test (libraries alcotest ...) ...).
    4. Execution: Run tests using dune runtest.
    $ opam install --deps-only --with-test .
    
    $ dune runtest
  4. Use Alcotest with Lwt for async tests

    main

    For asynchronous testing, use the Alcotest_lwt module. Instead of unit -> unit, your test functions will have the type unit -> unit Lwt.t.

    Features:

    • Async Exception Handling: If an async exception occurs, Alcotest will cancel the test case and fail it rather than crashing the process.
    • Resource Cleanup: Alcotest_lwt.test_case provides a switch. You can use Lwt_switch.add_hook with this switch to ensure resources are freed when the test finishes or fails.

    Wrap your suite in Lwt_main.run.

    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
        ]
      ]
  5. Pass custom options to tests using run_with_args

    main

    If your test functions require extra parameters (type 'a -> unit instead of unit -> unit), use Alcotest.run_with_args.

    You must provide a Cmdliner.Term to define how the extra parameter is parsed from the command line. Note that only optional arguments are supported; positional arguments are not allowed.

    let test_nice i = Alcotest.(check int) "Is it a nice integer?" i 42
    
    let 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]
      ]
  6. Configure test.exe execution via command line options

    main

    Use the following options to modify how test.exe behaves during execution:

    • --bail: Stop running tests immediately after the first failure.
    • -c, --compact: Use compact output format.
    • --color=WHEN: Set color output (auto, always, or never).
    • -e, --show-errors: Display the details of test errors.
    • --json: Output results in JSON format (ideal for scripting).
    • -o DIR: Specify a directory to store test log files.
    • -q, --quick-tests: Run only the tests designated as 'quick tests'.
    • --tail-errors=N: In case of an error, show only the last N lines of output.
    • -v, --verbose: Display full test outputs. Warning: Using this prevents output logs from being available for later inspection.
    test.exe --bail --compact --color=always --show-errors --json -o ./logs -q --tail-errors=10 -v
  7. Configure test.exe via environment variables

    main

    You can control test.exe behavior without command line arguments by setting the following environment variables:

    VariableDescription
    ALCOTEST_BAILEnables --bail behavior
    ALCOTEST_COLORSets --color mode (auto, always, never)
    ALCOTEST_COLUMNSNumber of columns before truncation (defaults to auto-detect or 80)
    ALCOTEST_COMPACTEnables --compact output
    ALCOTEST_QUICK_TESTSEnables --quick-tests mode
    ALCOTEST_SHOW_ERRORSEnables --show-errors
    ALCOTEST_SOURCE_CODE_POSITIONWhether to guess source code position on failure (defaults to true)
    ALCOTEST_TAIL_ERRORSSets --tail-errors=N
    ALCOTEST_VERBOSEEnables --verbose mode
    CISet to 'true' if running in a CI system
    GITHUB_ACTIONSSet to 'true' to enable GitHub Actions annotations for errors and outputs
  8. Understand test.exe exit statuses

    main

    When running test.exe, the exit code indicates the result of the execution:

    • 0: Success.
    • 123: Indiscriminate errors reported on standard error.
    • 124: Command line parsing errors.
    • 125: Unexpected internal errors (bugs).
  9. Run a subset of tests using regex and testcase numbers

    main

    You can run specific tests or a subset of test cases using test.exe.

    • NAME_REGEX: A regular expression that matches the names of the tests you want to execute.
    • TESTCASES: A comma-separated list of test case numbers or ranges. Both - and .. are valid separators for ranges.

    Example usage:

    # Run tests matching 'user_auth' and specific test case numbers
    test.exe user_auth 4,6-10,19
    
    # Run tests matching 'api' using the '..' range separator
    test.exe api 1..5
    test.exe [NAME_REGEX] [TESTCASES]
  10. Select specific tests to execute

    main

    You can filter tests at runtime using a regular expression matching the test names, optionally combined with a comma-separated list of test numbers or ranges (e.g., 2,4..9).

    Note: You cannot filter by the human-readable test case name (e.g., Lower case); you must use the test name and its index number.

    CLI Syntax: ./your_test_binary test '<regex>' ['<numbers>']

    # Run tests matching 'concat'
    $ ./simple.native test '.*concat*'
    
    # Run test 'string-case' specifically at index 1 through 3
    $ ./simple.native test 'string-case' '1..3'
  11. List available tests with test.exe

    main

    Use the list command to see all available tests in the current suite. You can optionally specify the color mode using the --color option.

    Available color modes for --color=WHEN:

    • auto: Defaults to 'always' inside Dune, otherwise 'auto'.
    • always
    • never
    test.exe list [--color=auto|always|never]
  12. Control Alcotest Output Color

    main

    You can control the colorization of Alcotest output using the --color flag or the ALCOTEST_COLOR environment variable.

    Options for --color (or ALCOTEST_COLOR):

    • auto: (Default) Automatically detects if the output is a TTY. If running inside Dune, it defaults to always.
    • always: Forces ANSI color output.
    • never: Disables color output.
    # Example using CLI flag
    alcotest --color always
    
    # Example using environment variable
    ALCOTEST_COLOR=never alcotest