Unit Testing Library

Author(s): Edison Mera.

This library provides an extension of the Ciao assertion language which allows writing unit tests. The central idea is to use the assertion language to provide specifications of test cases for a given predicate. The package also provides some special properties that are convenient when specifying unit tests and the required run-time libraries.

In general, a test assertion is written as follows:

:- test predicate(A1, A2, ..., An) 
   :  <Precondition>
   => <Postcondition>
   +  <Global properties>
   #  <Comment>.

Where the fields of the test assertion have the usual meaning in Ciao assertions, i.e., they contain conjunctions of properties which must hold at certain points in the execution. Here we give a somewhat more operational (“test oriented”), reading to these fields: predicate/n is the predicate to be tested. Precondition is a goal that is called before the predicate being tested, and can be used to generate values of the input parameters. Postcondition is a goal that should succeed after predicate/n has been called. The idea appears to be simple, but note that due to the non-determinism of logic programs, the test engine needs to test all the solutions that can be tested up to given limits (for example, a maximum number of solutions, or a given time-out). Properties specifies some global properties that the predicate should meet, for example, not_fails means that the program does not fail, exception(error(a,b)) means that the program should throw the exception error(a,b), and so on. But there are some specific properties that only applies to testing specified in the module unittest_props.pl, for example times(N) specifies that the given test should be executed N times, try_sols(N) specifies that the first N solutions of the predicate predicate/n are tested. Comment is a string that document the test.

A convenient way to run these tests is by selecting options in the CiaoDbg menu within the development environment:

  1. Run tests in current module: execute only the tests specified in the current module.

  2. Run tests in all related modules: execute the tests specified in the module and in all the modules being used by this.

  3. Show untested predicates: show the exported predicates that do not have any test assertion.

Additional notes

  1. The test assertions allow performing unit testing, i.e., in Ciao, performing tests at the predicate level.

  2. The tests currently can only be applied to exported predicates.

  3. If you need to write tests for predicates that are spread over several modules, but work together, then it is best to create a separate module, and reexport to the predicates required to build the test. This allows performing integration testing, using the same syntax of the unit tests.

  4. The Ciao system includes a good (and growing) number of unit tests. To run all the tests among the other standard tests within the CiaoDE run the following (at the top level of the source tree):

    ./ciaosetup runtests
    


Usage and interface

  • Library usage:
    :- use_module(library(unittest)).

Known bugs and planned improvements

  • load_compilation_module, load_test_module and load_resource_module directives have similar behavior