Electric Froth

______ _ ______ ( / // _/_ o ( / _/_ / /-- // _ _, / _ , _, -/--_ __ / /_ (/____/(/_(/_(__(__/ (_(_(__ _/ / (_(_)(__/ /_


Nim! pt7 - Testing

by Joel Kleier on 2014-11-10

In my last post on Nim, I discussed modules a bit. This time around, I want to figure out the answer to "How do I test in Nim?"

First, very little comes up in basic searches. Mostly you get reference to using the when statement (compile-time if) along with assert and company, but that is fairly primitive.

Doing some more digging, I found that a unittest library does actually exist in the standard libs, but it is not linked to from anywhere becase it requires better documentation. If you do a search on the Nimrod repository, though, you can find that there are some examples of the libraries use! However, there’s probably a reason for it not being listed in the documentation besides a lack of documentation for itself.

So, another way to do tests, if you look at the Nim compiler source itself, is to just create a directory with individual modules that contain nothing but code for performing tests.

I decided to use a small vector math library for motivation to explore the testing facilities (that are not unittest), and to see how I might incorporate testing into a larger project.

Here’s just a small part of the library that covers only a convenient way to initialize a TVec3 value:

  TVec3* = array[0..2, int]

proc init*(vec: var TVec3; x, y, z: int) =
  vec[0] = x
  vec[1] = y
  vec[2] = z

And here’s my testing code:

import vectors

var vec: TVec3
vec.init 1, 2, 3

assert(vec[0] == 1)
assert(vec[1] == 2)
assert(vec[2] == 3)

echo "OK"

Simple: create a TVec3, initialize it, assert values are what are expected, then give the "OK" if all the asserts pass.

The key to this approach is in the command used to build and execute the tests, since I use a make file, this test (and every other test) are, are in a test target that executes commands similar to:

nimrod c --verbosity:0 -p:./src/ -o:../bin/tests tests/tvectors.nim && ./bin/tests

This command does several things:

  1. sets --verbosity to 0 so that a bunch of mostly unimportant info isn’t printed to stdout

  2. adds the src directory to the path that Nim uses to search for modules

  3. sets the -o output file to a generic exe name

  4. specifies the test to build (tests/tvectors.nim in this case)

  5. and after a successful build, runs the tests with && ./bin/tests

With my above tvectors.nim tests, I get a simple OK printed to the console after each test is built and run. Otherwise I either get a compilation error message, or something more akin to:

Traceback (most recent call last)
tvectors.nim(6)          tvectors
system.nim(2908)         failedAssertImpl
system.nim(2136)         raiseAssert
Error: unhandled exception: vec[0] == 2  [EAssertionFailed]

Which is what gets displayed when an assertion fails.

Next time I talk about Nim, I tentitively plan on building out this vector library a little more and seeing how the tests scale. But I think a more pressing need might be the ability to specify the TVec3 type more generically so that I don’t have to re-declare types for integers, floats, etc.

Until next time!