This module implements boilerplate to make unit testing easy.
The test status and name is printed after any output or traceback.
Tests can be nested, however failure of a nested test will not mark the parent test as failed. Setup and teardown are inherited. Setup can be overridden locally.
Compiled test files return the number of failed test as exit code, while nim c -r <testfile.nim>
exits with 0 or 1
Specify the test name as a command line argument.
nim c -r test "my test name" "another test"
Multiple arguments can be used.
Specify the suite name delimited by "::"
.
nim c -r test "my test name::"
A single "*"
can be used for globbing.
Delimit the end of a suite name with "::"
.
Tests matching any of the arguments are executed.
nim c -r test fast_suite::mytest1 fast_suite::mytest2 nim c -r test "fast_suite::mytest*" nim c -r test "auth*::" "crypto::hashing*" # Run suites starting with 'bug #' and standalone tests starting with '#' nim c -r test 'bug #*::' '::#*'
suite "description for this stuff": echo "suite setup: run once before the tests" setup: echo "run before each test" teardown: echo "run after each test" test "essential truths": # give up and stop if this fails require(true) test "slightly less obvious stuff": # print a nasty message and move on, skipping # the remainder of this block check(1 != 1) check("asd"[2] == 'd') test "out of bounds error is thrown on bad access": let v = @[1, 2, 3] # you can do initialization here expect(IndexError): discard v[4] echo "suite teardown: run once after the tests"
TestStatus = enum OK, FAILED, SKIPPED
OutputLevel = enum PRINT_ALL, ## Print as much as possible. PRINT_FAILURES, ## Print only the failed tests. PRINT_NONE ## Print nothing.
TestResult = object suiteName*: string testName*: string ## Name of the test case status*: TestStatus
nil
if the test case is not in a suite. OutputFormatter = ref object of RootObj
ConsoleOutputFormatter = ref object of OutputFormatter colorOutput: bool outputLevel: OutputLevel ## Set the verbosity of test results. ## Default is ``PRINT_ALL``, unless ## the ``NIMTEST_OUTPUT_LVL`` environment ## variable is set for the non-js target. isInSuite: bool isInTest: bool
stdout
is a tty. Setting the environment variable NIMTEST_COLOR
to always
or never
changes the default for the non-js target to true or false respectively. The deprecated environment variable NIMTEST_NO_COLOR
, when set, changes the defualt to true, if NIMTEST_COLOR
is undefined. JUnitOutputFormatter = ref object of OutputFormatter stream: Stream testErrors: seq[string] testStartTime: float testStackTrace: string
abortOnError: bool
NIMTEST_ABORT_ON_ERROR
environment variable is set for the non-js target. proc addOutputFormatter(formatter: OutputFormatter) {...}{.raises: [], tags: [].}
proc newConsoleOutputFormatter(outputLevel: OutputLevel = PRINT_ALL; colorOutput = true): ConsoleOutputFormatter {...}{. raises: [], tags: [].}
proc defaultConsoleFormatter(): ConsoleOutputFormatter {...}{.raises: [], tags: [ReadEnvEffect].}
y < x
. proc newJUnitOutputFormatter(stream: Stream): JUnitOutputFormatter {...}{. raises: [Exception], tags: [WriteIOEffect].}
stream
is NOT closed automatically when the test are finished, because the formatter has no way to know when all tests are finished. You should invoke formatter.close() to finalize the report. proc close(formatter: JUnitOutputFormatter) {...}{.raises: [Exception], tags: [WriteIOEffect].}
proc checkpoint(msg: string) {...}{.raises: [], tags: [].}
checkpoint("Checkpoint A") check((42, "the Answer to life and everything") == (1, "a")) checkpoint("Checkpoint B")
outputs "Checkpoint A" once it fails.
proc disableParamFiltering() {...}{.raises: [], tags: [].}
method suiteStarted(formatter: OutputFormatter; suiteName: string) {...}{.base, gcsafe, raises: [], tags: [].}
method testStarted(formatter: OutputFormatter; testName: string) {...}{.base, gcsafe, raises: [], tags: [].}
method failureOccurred(formatter: OutputFormatter; checkpoints: seq[string]; stackTrace: string) {...}{.base, gcsafe, raises: [], tags: [].}
stackTrace
is provided only if the failure occurred due to an exception. checkpoints
is never nil
. method testEnded(formatter: OutputFormatter; testResult: TestResult) {...}{.base, gcsafe, raises: [], tags: [].}
method suiteEnded(formatter: OutputFormatter) {...}{.base, gcsafe, raises: [], tags: [].}
method suiteStarted(formatter: ConsoleOutputFormatter; suiteName: string) {...}{. raises: [Exception, IOError], tags: [RootEffect, WriteIOEffect].}
styledWriteLine
. method testStarted(formatter: ConsoleOutputFormatter; testName: string) {...}{.raises: [], tags: [].}
method failureOccurred(formatter: ConsoleOutputFormatter; checkpoints: seq[string]; stackTrace: string) {...}{.raises: [], tags: [].}
y < x
. method testEnded(formatter: ConsoleOutputFormatter; testResult: TestResult) {...}{. raises: [Exception, IOError], tags: [RootEffect, WriteIOEffect].}
not (x == y)
. method suiteEnded(formatter: ConsoleOutputFormatter) {...}{.raises: [], tags: [].}
method suiteStarted(formatter: JUnitOutputFormatter; suiteName: string) {...}{. raises: [Exception, ValueError], tags: [WriteIOEffect].}
method testStarted(formatter: JUnitOutputFormatter; testName: string) {...}{.raises: [], tags: [TimeEffect].}
method failureOccurred(formatter: JUnitOutputFormatter; checkpoints: seq[string]; stackTrace: string) {...}{.raises: [], tags: [].}
stackTrace
is provided only if the failure occurred due to an exception. checkpoints
is never nil
. method testEnded(formatter: JUnitOutputFormatter; testResult: TestResult) {...}{. raises: [Exception, ValueError], tags: [TimeEffect, WriteIOEffect].}
y < x
. method suiteEnded(formatter: JUnitOutputFormatter) {...}{.raises: [Exception], tags: [WriteIOEffect].}
macro check(conditions: untyped): untyped
outputLevel
is not PRINT_NONE
). Example:import strutils check("AKB48".toLowerAscii() == "akb48") let teams = {'A', 'K', 'B', '4', '8'} check: "AKB48".toLowerAscii() == "akb48" 'C' in teams
macro expect(exceptions: varargs[typed]; body: untyped): untyped
import math, random proc defectiveRobot() = randomize() case random(1..4) of 1: raise newException(OSError, "CANNOT COMPUTE!") of 2: discard parseInt("Hello World!") of 3: raise newException(IOError, "I can't do that Dave.") else: assert 2 + 2 == 5 expect IOError, OSError, ValueError, AssertionError: defectiveRobot()
template suite(name, body) {...}{.dirty.}
Declare a test suite identified by name with optional setup
and/or teardown
section.
A test suite is a series of one or more related tests sharing a common fixture (setup
, teardown
). The fixture is executed for EACH test.
suite "test suite for addition": setup: let result = 4 test "2 + 2 = 4": check(2+2 == result) test "(2 + -2) != 4": check(2 + -2 != result) # No teardown needed
The suite will run the individual test cases in the order in which they were listed. With default global settings the above code prints:
[Suite] test suite for addition [OK] 2 + 2 = 4 [OK] (2 + -2) != 4
template test(name, body) {...}{.dirty.}
test "roses are red": let roses = "red" check(roses == "red")
The above code outputs:
[OK] roses are red
template fail()
abortOnError
is true. Otherwise, erase the checkpoints and indicate the test has failed (change exit code and test status). This template is useful for debugging, but is otherwise mostly used internally. Example:checkpoint("Checkpoint A") complicatedProcInThread() fail()
outputs "Checkpoint A" before quitting.
template skip()
if not isGLConextCreated(): skip()
template require(conditions: untyped)
© 2006–2018 Andreas Rumpf
Licensed under the MIT License.
https://nim-lang.org/docs/unittest.html