UnitTest
Usage
use UnitTest;
or
import UnitTest;
Support for automated testing in Chapel.
The UnitTest module is intended to be used with the mason test command, which automates execution of any test function.
A unit test function is defined as any function with the following signature:
proc funcName(test: borrowed Test) throws {}
These functions must accept an argument of type borrowed Test
, and have a
throws
.
A program containing tests must execute the UnitTest
main()
function to run the tests.
Assert Functions
Here are the assert functions available in the UnitTest module:
Test Metadata Functions
UnitTest module also provides multiple methods for specifying test Metadata:
Examples
All examples are run using the mason test command, which acts as a test runner for the UnitTest module. See Testing your Package for more info.
Note
These examples can also be run standalone, but that output is not shown here.
Basic Usage
Here is a minimal example demonstrating how to use the UnitTest module:
use UnitTest;
proc celsius2fahrenheit(x) {
// we should be returning "(x: real * 9 / 5) + 32"
return (x * 9 / 5) + 32;
}
proc test_temperature(test: borrowed Test) throws {
// we were expecting 98.6 but since we missed typecasting
// the above function returned 98.
test.assertFalse(celsius2fahrenheit(37) == 98);
}
UnitTest.main();
Output:
======================================================================
FAIL BasicUsage.chpl: test_temperature()
----------------------------------------------------------------------
AssertionError: in BasicUsage.chpl:17 - assertFalse failed. Given expression is True
----------------------------------------------------------------------
FAILED (failures = 1 )
Skipping Tests
You can skip tests unconditionally with skip
and
conditionally with skipIf
:
use UnitTest;
/* calculates factorial */
proc factorial(x: int): int {
return if x == 0 then 1 else x * factorial(x - 1);
}
/*Conditional skip*/
proc test1(test: borrowed Test) throws {
test.skipIf(factorial(0) != 1, "Base condition is wrong in factorial");
test.assertTrue(factorial(5) == 120);
}
/*Unconditional skip*/
proc test2(test: borrowed Test) throws {
test.skip("Skipping the test directly");
}
UnitTest.main();
Output:
======================================================================
SKIPPED Skip.chpl: test2()
----------------------------------------------------------------------
TestSkipped: in Skip.chpl:22 - Skipping the test directly
----------------------------------------------------------------------
OK (passed = 1 skipped = 1 )
Specifying locales
You can control the number of locales a test should use with these methods:
addNumLocales
maxLocales
minLocales
Here is an example demonstrating how to use addNumLocales
proc test_square(test: borrowed Test) throws {
test.addNumLocales(5);
var A: [Locales.domain] int;
coforall i in 0..<numLocales with (ref A) {
on Locales(i) {
A[i] = (i+1) * (i+1);
}
}
test.assertTrue(A[4] == 25);
}
Output:
----------------------------------------------------------------------
OK (passed = 1 )
You can also specify multiple locales on which your code can run.
proc test3(test: borrowed Test) throws {
test.addNumLocales(5, 3);
}
You can specify the range of locales using maxLocales
and
minLocales
proc test4(test: borrowed Test) throws {
test.maxLocales(4);
test.minLocales(2);
}
Specifying Dependencies
You can specify the order in which tests should run using dependsOn
:
use UnitTest;
use List;
var factorials: list(int);
// calculates factorial
proc factorial(x: int): int {
return if x == 0 then 1 else x * factorial(x - 1);
}
proc testFillFact(test: borrowed Test) throws {
test.skipIf(factorial(0) != 1, "Base condition is wrong in factorial");
for i in 1..10 do
factorials.pushBack(factorial(i));
}
proc testSumFact(test: borrowed Test) throws {
test.dependsOn(testFillFact);
var s = 0;
for i in factorials.indices do
s += factorials[i];
test.assertGreaterThan(s, 0);
}
UnitTest.main();
Output:
----------------------------------------------------------------------
OK (passed = 2 )
Filtering Tests
When running tests, you can run a subset of the tests in a given file by using specifying a filter. This is done by specifying --filter
followed by a regular expression matching the names of the tests to run.
Note
If you are using a build of Chapel without regex support
(i.e. CHPL_RE2=none
), you can compile your test case with -snoRegex
to disable regex support in the test runner. --filter
will then
perform simple substring matching instead of regex matching.
- class Test
- proc skip(reason: string = "") throws
Unconditionally skip a test.
- Arguments:
reason – the reason for skipping
- Throws:
TestSkipped – Always
- proc skipIf(condition: bool, reason: string = "") throws
Skip a test if the condition is true.
- Arguments:
condition – the boolean condition
reason – the reason for skipping
- Throws:
TestSkipped – If the condition is true.
- proc assertTrue(test: bool) throws
Assert that
test
is true.- Arguments:
test – the boolean condition
- Throws:
AssertionError – If the assertion is false.
- proc assertFalse(test: bool) throws
Assert that
test
is false.- Arguments:
test – the boolean condition
- Throws:
AssertionError – If the assertion is true.
- proc assertEqual(first, second) throws
Assert that
first == second
.- Arguments:
first – The first object to compare.
second – The second object to compare.
- Throws:
AssertionError – If both the arguments are not equal.
- proc assertRegexMatch(x: ?t, pattern: t) throws
Assert that x matches the regular expression pattern.
Warning
This method requires Chapel to be built with CHPL_RE2=bundled.
- Arguments:
x – The first string or bytes to match.
pattern – The regular expression pattern.
- Throws:
AssertionError – If x doesn’t match the regex
- proc assertRegexMatch(x: ?t, re: regex(t)) throws
Assert that x matches the pre-compiled regular expression object.
Warning
This method requires Chapel to be built with CHPL_RE2=bundled.
- Arguments:
x – The first string or bytes to match.
pattern – The pre-compiled regular expression object.
- Throws:
AssertionError – If x doesn’t match the regex
- proc assertNotEqual(first, second) throws
Assert that
first != second
.- Arguments:
first – The first object to compare.
second – The second object to compare.
- Throws:
AssertionError – If both the arguments are equal.
- proc assertGreaterThan(first, second) throws
Assert that
first > second
.- Arguments:
first – The first object to compare.
second – The second object to compare.
- Throws:
AssertionError – If the first argument is not greater than second argument.
- proc assertLessThan(first, second) throws
Assert that
first < second
.- Arguments:
first – The first object to compare.
second – The second object to compare.
- Throws:
AssertionError – If the first argument is not less than the second argument.
- proc maxLocales(value: int) throws
Specify maximum number of locales this test can run on.
- Arguments:
value – Maximum number of locales with which the test can be run.
- Throws:
UnexpectedLocales – If value is less than 1 or minNumLocales
- proc minLocales(value: int) throws
Specify minimum number of locales required to run the test.
- Arguments:
value – Minimum number of locales with which the test can be run.
- Throws:
UnexpectedLocales – If value is more than maxNumLocales
- proc addNumLocales(locales: int ...?n) throws
Indicate how many locales to run the test on.
If a test can run on multiple different locale counts, they can be specified using multiple arguments. Only one of the locale counts specified will be run in testing.
Note
To run a single test with multiple locale counts, create multiple tests where each test requires a specific locale count.
- Arguments:
locales – locale counts
- Throws:
UnexpectedLocales – If locales are already added.
- proc dependsOn(tests: argType ...?n) throws
Adds the tests which must run before this test.
- Arguments:
tests – First class functions
- Throws:
DependencyFound – If called for the first time in a function.
- proc main() throws
Runs the tests
Call this as
UnitTest.main();