Skip to content

Unit Testing

Paul Manias edited this page May 7, 2024 · 2 revisions

Automated testing is an important part of Parasol's build process, and can help to ensure that new changes do not have unexpected consequences for existing code.

We use our own command-line script, Flute, to run tests and evaluate their success. Flute can be run directly from the terminal, but is primarily intended for use in CMake build scripts to ensure that tests are being run as part of the build and release process.

A typical run of Flute from the terminal can look like this:

parasol --log-warning --gfx-driver=headless scripts/def/flute.fluid file=test_script.fluid

Usage in CMake is straight-forward using the following template:

flute_test (target_name "flute_file.fluid")

The target_name is a unique name for the test and flute_file.fluid is a reference to the test script.

Try to avoid bundling all your tests into one file. Ideally, your tests will be grouped into common categories that can be broken out across a number of files. Use as many calls to flute_test() as necessary, and give each a useful target_name for CMake's test report.

Test Scripts

Flute works by running the provided test script immediately. It is important that the script does not perform any initial activity when this occurs. Flute's expectation is that a table is returned from the script, and this must describe the tests that are to be activated.

The resulting structure should follow this template:

return {
   tests = {
      'testA', 'testB', ...
   },
   init = function()
      ...
   end,
   cleanup = function()
      ...
   end
}

The init and cleanup values are optional. The init function will be called prior to running any tests, and cleanup is called post-testing. It is guaranteed that the cleanup process will run even if an exception is thrown by a test.

The tests table is a list of function names that will be called, each of which must represent a test. The tests will be run in the order specified.

Exceptions

Exceptions are used to determine whether or not a test has succeeded.

The assert() function can be used to confirm that a value is set correctly, and if not, raise an exception with the provided message.

Exceptions can otherwise be raised manually with error() messages.

A test should not be written in such a way as to intentionally pass through uncaught exceptions, as this implies that something unforeseen has occurred.