An Example C++ library with Unit Testing

Posted on

Recently I’ve found the need to do some basic C++ development. The last time I was writing C++ heavily I wasn’t far enough along in my career to have developed strong habits around unit testing (or testing in general). These days though I can’t really even think about writing useful code without having the ability to get some test coverage.

It took me a while to find an adequate unit testing framework, and then even after reading the documentation I couldn’t quite get an end-to-end example working. Add to that my lack of knowledge around CMake and you have the perfect storm for stagnation and a lack of productivity.

After some trial and error, some reading, and some frustration I eventually settled on a build and test flow that didn’t feel quite like total garbage. I decided to implement and document the structure and put it up on github for the world to mock and ridicule, and you can find the result there.

This post is just a quick overview and a bit of justification.

Goals

High-level I wanted to have a structure that allowed for me to keep my test code separate from my library code. Further, I didn’t just want this to be a directory separation, but go all the way through build. I.e. when someone builds the libary, the resulting binary doesn’t contain any of the tests.

I also wanted make sure that my dependency on the unit testing framework wasn’t something that required installation of a system wide package or header file. I felt that this would prevent me from isolating the unit testing framework as a dependency and could inhibit having multiple projects going simultaneously.

Lastly, even though the world has moved to CMake, it has some rough edges around the typical “extract, make, install” flow that the OSS world has become accustomed to. I wanted to use CMake for all the heavy lifting, but also leverage make as a bridge to maintain the common flow.

Solution

What I wound up with was a simple structure for laying out my library code that worked with CMake. I was able to leverage the Catch2 unit testing framework by bringing it in as a git submodule. I then created a bare-bones Makefile to wrap CMake so the flow of cloning and building the library matched expectations.

Trying it out

You can read the gory details in the README.md of the project, but what you need to do to try this out is pretty simple:

git clone https://github.com/davidnewman/examplecpplib.git
git submodules update --init --recursive
make

The above commands should be obvious, but basically it grabs our repository, then grabs the tested version of Catch2, and then “builds”. In this case, the build is simply creating a directory to store all of CMake’s generated files and then invoke the resulting Makefile.

Just to show that the tests work, you can do either of the following:

make test
./artifacts/tests/tests

TODOs

As with anything, this first cut is intended to be an MVP. Here are a few things I’d like to do to make it better.

  • Modify the Makefile so that it does the git submodule work.
  • Alternatively, see if CMake can grab Catch2 using some magic I am currently unaware of.
  • Add a documentation generator. This would allow us to auto-generate updated docs for the library each time we build.

Summary

I am sure there are alternative approaches to all of this. I just found this structure general purpose enough to support my current development needs and I couldn’t find any really good examples online that integrated all of the bits together. That being said, I am certainly not an expert, so I’d welcome any Issues and Pull Requests to make this better.