Unit testing with OCaml
Tags: 100daystooffload, ounit2, unittesting, ocaml
Published: 2023-09-17 19:54:28

One of the first steps when I'm starting to learn a new programming language is to figure out how to do unit testing in that language. We are all wired differently, but unit testing is a perfect tool to experiment/testing syntax, features, scopes, and about everything in a programming language.

I recently picked up and started to play with [OCaml](https://ocaml.org/) and it has an awsome [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) (called [toplevel](https://v2.ocaml.org/manual/toplevel.html)) tool which is a great substitute for unit tests  to learn and testing the OCaml language for those that prefer that instead.

However lets try to set up a simple project with some unit tests with [Ounit2](https://github.com/gildor478/ounit). This assumes that OCaml with the build system [Dune](https://dune.readthedocs.io/en/stable/) is installed.

```bash
# Create project
dune init proj unit_test_example
cd unit_test_example

# Install the OUnti2 testing framework
opam install ounit2

# Open the IDE
code .
```

Navigate to the file, **main.ml**, should be located in the **bin** directory. 

![Explorer](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rdaodnhyhpoyi4rresxh.png)
Replace the current code in main.ml with this.

```ml
let () =
  match Sys.argv with
  | [| _; n |] -> Unit_test_example.Factorial.factorial (int_of_string n) |> print_int; print_newline ()
  | _ -> 
    print_endline "Usage: unit_test_example [n]";
    exit 64
```

The code above wants to use a function, **factorial**, that is defined in a module called **Factorial**. Jump to the **lib** directory and create the file, **factorial.ml**, there to start to solve that issue.

![factorial.ml](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g5cwlj0spzg4chhvfo3n.png)

In that file we will create the code that we want to test.

```ml
let rec factorial n =
  match n with 
  | 0 | 1 -> 1
  | _ -> n * factorial (n - 1)
```

Now it's time to create our tests for the factorial code. Open the file, **unit_test_example.ml** in the test directory and paste following code into that file.

```ml
open OUnit2

let test_factorial_of_zero _ =
  assert_equal 1 (Unit_test_example.Factorial.factorial 0)

let test_factorial_of_five _ =
  assert_equal 120 (Unit_test_example.Factorial.factorial 5)


let () =
  run_test_tt_main
    ("factorial tests" >:::
       [
         "factorial of zero" >:: test_factorial_of_zero;
          "factorial of five" >:: test_factorial_of_five;
       ])
```

Here we create two simple tests that asserts the expected value for factorial zero and five. The entry function, **let ()**, is then calling our test functions. Before we are able to run our unit tests we will need to configure our dune file to recognize the lib file, **factorial.ml**, first. Do this by open the file **dune** that is located in the test directory.

![dune file for test](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iecxo5v4cv2zfk5n1vqu.png)

This file should look like this.

```lisp
(test
 (name unit_test_example)
 (libraries ounit2 unit_test_example))
```

The third line is added to configure that the test library is aware of the [Ounit2](https://github.com/gildor478/ounit) library and our **unit_test_example** library.

We are now ready to run our unit tests.

![dune test](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o9a7sjqvw2u2sg2uz1ob.png)

Now we have something to tinker with to explore the OCaml land.

And if you would like to run the program from the CLI you can execute it like this.

```sh
# Where 5 is the factorial to calculate
dune exec ./bin/main.exe -- 5
```

Happy testing!