Test Discovery
Test discovery is the process of automatically finding test files, so you don't need to manually manage your imports and write out top-level test trees.
For the purposes of this discussion, let's assume a somewhat complex test suite with different kinds of tests, laid out on disk like the following. The key point is that different groups of tests may require different contexts: for example, UnitTests
have no dependencies but SeleniumTests
require Selenium context.
In Main.hs
, we want to automatically generate something like this:
#
The basic setupAutogenerating the tests in a given module requires two pieces of code in that module: 1) A CPP pragma to generate the imports, and 2) a Template Haskell call to generate the test tree. (Unfortunately it can't be done solely with Template Haskell, because TH cannot generate imports.)
To autogenerate tests for the example above, we'll apply autodetection separately in UnitTests.hs
and SeleniumTests.hs
. You can follow along with the full example here.
In the code below, the OPTIONS_GHC
pragma invokes the sandwich-discover
executable, which searches for modules underneath the current module (i.e., matching SeleniumTests.*
). Then it inserts the imports wherever it finds the special #insert_test_imports
token.
Finally, the code below calls getSpecFromFolder
in a TH spec to generate the actual test tree.
Once we write similar boilerplate in UnitTests.hs
, we can pull both sub-trees together into the main top-level tree below.
#
Running individual test modulesHaving set up test autodetection as above, we can now take advantage of the ability to run individual test modules. When you run with --list-tests
, you'll see a list of special flags you can pass. When you pass any of these flags, Sandwich will run only that test module.
note
You can always run individual test subtrees by simply passing --filter "some filter string"
with an appropriate filter string. However, this will filter the tree to any nodes that match the filter string, so it may not be as convenient to exactly match the subtree corresponding to a single module.
#
Main function autodetectionSometimes you want to include a main
function in an individual test module. These main functions can be convenient when you want to iterate on a single test module within a GHCi session, for example.
Sandwich can discover the presence of these main
functions and give you the ability to run them using the individual module flag. It does this using some magic.
If this has happened, Sandwich will indicate it by putting an asterisk next to the module name. For example, if UnitTests2.hs
had its own main function inside, you would see the following.
Thus, passing --unit-tests2
would result in that file's main
function being invoked, rather than the normal one in Main.hs
.