Home > Software design >  Using dune qtest in a multi-file project
Using dune qtest in a multi-file project

Time:10-12

Let me begin by saying that I'm a complete beginner in OCaml, so if I seem to have made some weird choices, I'm most likely not aware of them being a choice.

I am trying to get unit testing working in my project. After some searching I settled on qtest.lib.

I've set up my project as follows:

$ mkdir mylib
$ cd mylib
$ dune init lib mylib

In the dune file, I've written:

(library
 (name mylib)
 (inline_tests (backend qtest.lib)))

In mylib.ml, I've put the following code:

let foo x = x   2

(*$T foo
  foo 2 = 4
*)

At this point, everything works as expected:

$ dune runtest
Info: Creating file dune-project with this contents:
| (lang dune 2.9)
inline_test_runner_mylib alias runtest
random seed: 425752161
 [1 / 1] >foo>mylib.ml:4 *
 [1 / 1] >foo>;32;1mSUCCESS

The issues start if I try to introduce another file into the project. I created helper.ml with the following contents:

let bar x = 3 * x

(*$T bar
  bar 3 = 9
*)

Now, dune runtest errors out with

$ dune runtest
File "mylib.ml", line 11, characters 5-11:
Error: Unbound module Helper

In some of my other attempts at reproducing it, the file mentioned was instead _build/default/.mylib.inline-tests/inline_test_runner_mylib.ml-gen.

I first assumed that this means I'm organizing my files incorrectly. However, I can access Helper.bar within mylib.ml:

$ cat mylib.ml
let foo x = Helper.bar (x   2)
$ dune build     # no errors

Thus I have no idea what the problem could be here. What's going on?

CodePudding user response:

Strangely it looks like you need to put

(modules)

in your dune file (as you can see here)

Your dune file will look like:

(library
 (name mylib)
 (modules)
 (inline_tests (backend qtest.lib)))

CodePudding user response:

Dune wraps library by default in a module with the same name as the library. For instance, defining a mylib library with

a.ml
b.ml

will create a Mylib module with A and B as submodule. However, if you define a mylib module by hand, dune consider that this module is the entry point of your library, and it is your responsibility to expose all visible submodule. Thus if you define mylib.ml as:

let x = 0

you are explicitly hiding the Helper module. The simpler option here is probably to rename the Mylib module.

Another issue is that the qtest backend does not seem aware of dune wrapping libraries. A potential workaround is to define your own inline test backend and add an open Mylib to the preamble


(library (name myqtest)
 (modules)
 (inline_tests.backend
  (runner_libraries qcheck ounit2 bytes)
  (generate_runner (run qtest extract --preamble "open Myib" --quiet  %{impl-files} %{intf-files}))
 )
)

(library (name mylib) 
 (inline_tests
  (backend myqtest)
 )
)

(I hope that I am missing an option and that there is a simpler solution to send a flag to the runner generator)

  • Related