I am writing fast C++ libraries for work and need to wrap them in unit tests to ensure that they continue to operate and perform as they evolve. My number one constraint is that these libraries must be dependency-free. The only tools that I may use to compile or install these libraries on any platform (in my case OS X and Linux) is a C++11 compiler and a C++ standard library. Nothing else.
This dependency-free requirement precludes the use of excellent popular testing frameworks such as Boost Test (a dependency), cppunit (not up to C++11 yet), google-test (uses a dylib or library depending on the platform) or XCTest (Xcode only and not C++).
Catch is a single header only, dependency-free, lightweight testing framework that’s perfect for my needs. It’s simple to add to a project, simple to create tests cases and scenarios and simple to run. It also allows the user to run only a subset of tests using tags, which is really cool.
And that’s why I chose it.
catch.hpp in a target and you’re halfway there.
Catch is well documented. I recommend you follow the tutorial for simple functional unit tests and how to use the product. Since there is no point in me repeating how to write simple tests, go ahead and read through the tutorial, and I’ll wait until you return.
PLAYS ON-HOLD MUSAK
Ok, back? Good. You have seen how simple it is to spin up a
TEST_CASE, break it down into several
SECTION elements and test results using
Lets do something more complex, lets test a sample class. This sample project is what I used to test Catch when I first saw it and helped me choose it.
First, the tests:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
In this example, we have a single
TEST_CASE and three sections. Inside the
TEST_CASE we instantiate the object and each
SECTION tests a function in the sample class. Note that in the example, I arbitrarily switch between
CHECK (no stop test) and
REQUIRE (stop test), whereas in a real testing environment, I use them appropriately.
Here’s the sample class that we’re testing’s header, it really is quite a useless class but gives us a range of things to try:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
And its body:
1 2 3 4 5 6 7 8 9 10
Testing In Xcode
I setup testing in Xcode using a separate tests folder and a second tests target and scheme. In this sample case, the main project code is in the
SampleProject group (usually a library project) and the test target code is in the
TestSampleProject group. This group (and its matching file system folder) are automatically created when you add an Xcode command-line target.
To create this target, select the project at the top and click
+ or choose File \ New \ Target from the menu, choose OS X \ Application \ Command Line Tool, choose
C++ as the language and give it a name.
I then add
catch.hpp and edit the
main.cpp file. The
main.cpp in the test target uses the default Catch main function, there is no point in writing my own:
I also add the following command-line options to the test target scheme and toggle when needed:
-r consolesets up readable console output (not necessary but a good reminder)
-d yesshows the time taken on each test (usually disabled)
sverbosely displays tests (usually disabled)
- You could also add any test tags you want to run as an option, but I find most of my test projects run sufficiently fast that I usually leave this out and run all tests. It also protects me from forgetting to run the full test suite.
I then start to add
.cpp files for each test case and write my tests.
Finally, you also need to add each class that is being tested to the Test target as well or it will not compile.
Running the test target delivers the following console output on success:
If any test cases fail, you get:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Correct the failures. Then add more tests. Run. Iterate, iterate, iterate. You know how to unit test.
You can download the sample project to see how it works from here.
I have been using Catch for several weeks now in multiple C++ projects and it’s been wonderful. Setup is easy, adding test cases is simple, running tests is a keystroke away and evolving my core dependency-free libraries is easier and more reliable than ever.
Follow the author as @hiltmon on Twitter.