Practical Testing: 41 - GoogleTest

I’ve been writing a series of blog posts, called “Practical Testing”, about testing real-world, multi-threaded code. Up until now I’ve used my own, home grown, unit testing framework. When I started out with this series back in 2004 there wasn’t much in the way of mature testing frameworks for C++ and, over the years I haven’t really found a need to switch from my own stuff that I understand and that works pretty well. I’ve recently been looking at GoogleTest for a client and decided that it’s worth seeing how I get on with it. The integration with the Visual Studio test explorer is quite useful (when it works) and the integration with Resharper++’s test explorer is similar but more reliable.

Integrating GoogleTest with my code was reasonably painless once I’d played around with the various options and decided to do it in my own way… I tried integration using CMake and, whilst it works well in both Visual Studio and CLion and provides a cross-platform solution it wasn’t quite convenient enough for me given the structure of most of my code and the fact that I tend to work with Visual Studio projects and understand them better than I do CMake. I tried the nuget approach using the ‘Microsoft magic’ of creating a new project of the correct, ‘googletest’, type and letting Visual Studio do all of the clever stuff for me, and whilst that worked fine I didn’t trust it to work painlessly with 2017, 2019 and 2022 (though I didn’t test it), and it didn’t appear to be something that I could also use as a cross-platform solution if I wanted to…

So, what I’ve done instead is add two new projects to my current Practical Testing solution. The first is a new test project for my CoreTools library; CoreToolsGoogleTest. This is similar to the existing Test project; CoreToolsTest and it contains just the tests. I’ve added two very simple tests, just to check things work…

The simplest looks like this:

#include "JetByteTools/Admin/Admin.h"

#include "JetByteTools/ThirdPartyCode/GoogleTest/gtest.h"

#include "JetByteTools/CoreTools/CallbackTimerQueue.h"

TEST(CallbackTimerQueue, TestConstruct)
{
   CCallbackTimerQueue timerQueue;
}

Note that I’m picking the GoogleTest header, gtest.h up from another new library that I’ve added. This, ThirdPartyCode/GoogleTest is a simple wrapper which uses a git submodule to check out googletest and builds it as a static library. I’m doing it this way because it makes it easy for me to set up the same build configurations with the same settings as all of my other projects and all of my existing tooling works with it without change. I cheat a little with a pre-build step that makes sure some symbolic links exist to make the google test header files easier to access; but you can pretty much forget about this project once it has built. For a cross-platform solution I would likely use CMake but with my custom structure and again, my existing tooling for CMake should just work. I expect this will evolve over time.

The second test uses my normal home-grown mock objects, linked in without change, and a googlemock mock object just to make sure that part of my integration also works.

Now that I have this very basic testing working I can look at making more complex mock objects with googlemock. Some of my mocks for threaded code have synchronisation points in them so that tests can wait on operations. I expect that my next step will be to make a gmock that derives from a partially implemented custom mock so that I can use the gmock EXPECT_CALL stuff with an object that can also wait for things to happen. After that I need to investigate how to convert my template based tests that test two different implementations of an object with one set of test code…

Code

The code is here on GitHub and new rules apply; The code will build with Visual Studio 2017, 2019 and 2022. CoreToolsGoogleTest is the solution that you want and the project that you should set as active (if you want to run the bulk of the tests then open the CoreToolsTest solution). The code uses precompiled headers the right way so that you can build with precompiled headers for speed or build without them to ensure minimal code coupling. The various options are all controlled from the “Admin” project; edit Config.h and TargetWindowsVersion.h to change things… By default the project is set to build for Windows 10; this will mean that the code WILL NOT RUN on operating systems earlier than Windows Vista as it will try and use GetTickCount64() which isn’t available.

For a simpler example of this way of using GoogleTest see the post on using testing to understand a new API.

This version of the code is licensed under the MIT license.