Jbuilder 1.0+beta19 has just been released in opam. There are several exciting new features in this release, but one I think deserves special attention is the newly added support of inline tests.
Inline tests allow to embed tests directly in the library code, in order to have the tests close to the tested functions or simply has a general framework to write unit tests. Setting up such tests usually require to write some tedious build system boilerplate, which has been implmented correctly once and for all in Jbuilder. All you need to do get jbuilder to build and run your tests is write (inline_tests) in your jbuild file.
The support in Jbuilder is completely generic, and can be used with various backends such as ppx_inline_test or qtest. Defining a new backend is very easy and the manual explains how to do it.
Example 1: using ppx_inline_test
Ppx_inline_test is an inline tests framework developped by Jane Street. As its name suggest, it relies on a ppx rewriter. Starting from version v0.10.1, ppx_inline_test works smoothly with Jbuilder by simply adding (inline_tests) to the jbuild file. For instance:
This is awesome, however, for the life of me I can’t figure out how to get the (glob) and (regexp) features to work. Are they broken in this release?
This is a great new and would drastically simplify testing. But just for showing interest not request, I want to see easy integration of quick check style test (property based test with random test data generation). Sometimes testing on several hand-crafted values are not enough.
@rdavison, we consider (glob) and (regexp) to be a design mistake, as they break the normal workflow: when you accept the correction you have to go back and edit the expectation. In practice this is a pain, it is much better to process the output to get rid of noisy parts.
There is a flag to allow support for (glob) and (regexp), but we are planning to get rid of output patterns entirely soon, so I don’t recommend using it.
We have an expect_test_helpers_kernel library that helps writing expect tests and process the output, for instance to hide file positions.
@yoriyuki this feature is mainly about the workflow, then you are free to use any testing library to write the tests themselves. I know that in Core_kernel and Core we support quick check and every module has generators.
I am having an issue where inline tests depend upon static files located outside the src directory since jbuilder runs tests from within that directory. Take for example the following:
inline test located in foo/src/foo.ml
depends upon foo/static/file.file
The solution I have come upon is to add a deps clause to the the inline_tests stanza that copies the static folder. This creates a directory structure in the _build that mirrors what exists in the repo. So, in my tests, I would access that file relatively via ../static/file.file.
However, it seems wrong to have to do this for every static directory being used, is there a recommended way to do this?
Should I move static into src? I’m not sure that would solve the issue of having to specify every directory to be copied.
Or is there a way to specify which directory the tests should be run from? Perhaps a setting to run the tests from the workspace root? I see that jbuilder does:
cd _build/default/foo/src && ./.foo.inline-tests/run.exe
Having it run in the root would also solve my problems since no copying is needed and foo/static can be referenced directly.
However, it seems wrong to have to do this for every static directory being used, is there a recommended way to do this?
Why does it seem wrong? Jbuilder needs to know what files every command will read in order to schedule commands and avoid re-running commands in incremental builds, so you do need to specify dependencies for tests.
Perhaps wrong is the incorrect word, I was wondering if there was a better way to have the behavior I want. Your explanation makes sense for the case where static needs to be copied into the build.
Is there a way to accomplish the latter(have inline tests run from SCOPE_ROOT)? Although I anticipate the answer is that I shouldn’t use (inline_tests) since the default behavior works for the majority of people and this is a an unusual case and I probably shouldn’t be depending on static files in inline tests in the first place.
EDIT:
The solution that seemed to be the best for my situation ended up being utilizing (inline_tests) to build the tests and then defining a custom alias that does chdir before running the test binary rather than using runtest. jbuilder is able to see that .foo.inline-tests/run.exe depends upon the inline tests.
There is no way at the moment. In general running things for the directory where they are defined is more modular: for instance you can do mv foo bar/foo and everything will still work as it should without having to modify the tests.
Thanks for the quick replies. Yes, it is definitely better to not have these inter-directory dependencies but it is unfortunately unavoidable for myself at the present. The workaround above is sufficient though, all in all jbuilder is still a 100x improvement over the build system that was in use previously.
It’s not a problem of having inter-directory dependencies. It’s just that you should make your build system aware of them for the reasons explained by Jeremie. The usual reason why tests are hard coded to run in a certain directory is that they expect fixtures to exist in a certain place. If you want to specify those places relative to your project root, you should simply make your tests aware of what the project root is. E.g. PROJECT_ROOT=$(git root) jbuilder runtest.
Note that you should still specify the dependencies using relative paths.
Probably not possible in the current version of dune. Dune discovers inline tests (and other) backends from the dependencies you list as preprocessors and libraries. What you can try and do is use the per_module specification for preprocess to limit your use of classical ppx to a single module. Elsewhere, you can use ppx_inline_test as usual.
Only for different modules. See per_module in the documentation.
Ah cool. Now, is there a way in a per_module to say “all modules except X and Y”? Like the :standard \ ... clause for library modules? I couldn’t find way to handle this.
@grayswandyr, there is no way at the moment but this could be added. Feel free to open a ticket about it
@Aurelie_H, try reinstalling ppx_inline_test. If it was installed with an older version of jbuilder and then jbuilder was upgraded with ppx_inline_test being reinstalled it won’t work
from where do you try to run the tests? Also, what is the contents of ppx_inline_test.dune in the directory reported by ocanlfind query ppx_inline_test?