Shipyard — a Tiny C++ Testing Library

Manan
3 min readMay 23, 2020

--

An anchor.

Writing unit tests is considered an integral aspect of software development. So much so that most modern programming languages ship with some in-house testing pipeline — be it Python’s unittest module or Go’s testing package. In addition to great library functions for testing, they have excellent command-line tools as well. But one of their most defining features is that they’re ridiculously easy to use. That is a valuable attribute a language gains with support for first-class testing. But C++ is a decades-old language and thus there exist no standard libraries for unit testing.

That’s not to falsely signal at a lack of testing libraries for C++. Rather, Google’s googletest library is probably the most popular unit testing framework out there. But as mentioned above, there is a stark lack of easy to use testing libraries. This prompted me to develop my own testing library called shipyard.

It is a header-only library that provides several custom Assert functions and similar derivatives alongside a generic runner function that sorts functions alphabetically and runs them.

This post is meant to be a tutorial for Shipyard that introduces writing tests, custom Asserts and using the ship CLI tool that comes with Shipyard for automated test discovery and code generation. Let’s start with a simple prime library that we wish to test. So we’ll start off with a C++ file called primelib.cpp inside of our root directory.

Simple and clean and basic functions for a prime number library. So far, so good. Now let’s add a file called test_primelib.cpp

Let’s walk through the new file. We first include the only Shipyard dependency we need — a single header file. Then we include the file (or header) that contains the functions we wish to test. Next, we define our functions. The Shipyard runner is meant to be used for special test functions that require no arguments and do not have a return. In template speak, it only accepts std::function<void(void)> .

Shipyard comes with a number of Asserts for checking equality and we use them to check for the output of the functions we wish to test.

There is no meta macro or templating programming going underneath for Asserts or naming conventions but Shipyard follows the standard of naming test files with the format — test_<name>.cpp and having the name of each test for function as test_<function_name> followed by a suffix containing more information or just a number; for instance, test_is_prime_even_nums or test_is_prime2.

This convention is highly recommended since it is used by ship — a command-line code generator for Shipyard. It scans a provided directory, or the current one if none, and looks for C++ files with the name prefix test_ and inside of them, searches for functions that have the same prefix. Now, in this directory run the ship.py script and let it generate the actual runner.

$ ship.py -v

Pass the -v flag for verbosity and it should generate the following code.

And that is it! You can now compile test.cpp with the appropriate flags although none are needed in this case and it should work.

Now for a few more things — to describe your own Assert function for a custom type, all you need to do is create a function with a name corresponding to Assert<class_name> followed by an optional class name (or some other verb you wish to assert) or simply Assert and overloading will take care of calling with the apt arguments. For example, you have a class called Person that has a family attribute. You want to create an Assert function for objects of Person with the same family.

Or something similar.

To view a reference of all the Assert functions provided you can read the reference documentation over at the repository.

--

--

Manan
Manan

Written by Manan

Computer Science and Mathematics enthusiast. I dabble in Philosophy.

No responses yet