This post covers my recent experience with unit testing and mocking in C++. By way of an introduction I was a slow convert to Test Driven Development, mostly due to the lack of it in my first couple of jobs. Once you use it properly though and understand its value, it becomes less of an optional extra and more of a necessity for maintainable development. I heard a statement about unit and acceptance tests the other day that I strongly agreed with:
- You can’t stay agile without clean code.
- You can’t have clean code without refactoring.
- You can’t refactor without good automated tests.
I always dreaded big refactors and the inevitable regression bugs that would creep in as a result of changing code without automated means to verify the refactor. Now I’d never willingly embark on a task like that without first understanding the functionality through unit tests. There’s a time and a place of course, and I don’t tend to drive out spikes or POCs with tests: as stated previously, my approach to Snake and Tetris was to hack it out and ask questions later.
Recently though, I’ve wanted to apply this to the projects with which I’m teaching myself C++. My background is in Java, for which there are many well-maintained unit testing frameworks like JUnit and TestNG and mocking frameworks like jMock and Mockito and I wanted equivalents for C++. I wanted to steer clear of Boost until my C++ understanding is better, so had a look around for other frameworks.
Google have two excellent frameworks - one for unit testing and one for mocking - in their gtest and gmock libraries. These seem to be the leading frameworks for C++ testing, or at least they’re the ones that are most frequently maintained! gtest allows you to express test cases and tests in the following way:
But lately I’ve been spoiled by the nearly human readable syntactic sugar in the various flavours of ScalaTest and I wanted something more than gtest’s powerful, yet robotic style. So as an alternative, I started using a library called Bandit which uses C++ lambda expressions to allow for unit tests to be defined in a style similar to Ruby’s rspec. This builds on a library for readable assertions and matchers called the Snowhouse framework which was put together by the same guy - Joakim Karlsson - and allows you to express tests in a more readable format:
Looking good so far, but what about mocks? Well there is no Bandit mocking equivalent so gmock is the way to go. Fortunately, gmock’s syntax feels friendlier than gtest’s, probably owing to the fact that not everything is caps! Two important functions look unpleasant however - ON_CALL which is used to dictate what a mock object should do on a given function call, and EXPECT_CALL which is used to declare what interactions are expected on a particular mock object. This gives you something that looks like:
This is almost the code I want to see! How can we make this better? Let’s create two function macros for ON_CALL and EXPECT_CALL to something that improves readability:
Much better! Bandit and gmock now look seamless together and my unit tests are really readable.
Having readable tests makes them less of a chore to write in the first place and easier to understand later. Bandit really helps facilitate this, and I’ve found it to be a refreshing look at C++ unit tests, borrowing stylistically from rspec and making good use of C++11’s lambda expressions.
The BDD style function macros for gmock are as a gist.