Categories
Geek / Technical

Converting from UnitTest++ to Google Test

Converting UnitTest++ To Google Test

In 2008, I wrote Test-Driven Game Development, which was more about being reintroduced to Test-Driven Development (TDD) and asking if other game developers use it regularly.

Around the time, Noel Llopis had written a survey of C++ unit test frameworks, and eventually co-wrote UnitTest++ as none of the existing frameworks were sufficient for his needs.

I’ve used it ever since.

At my day job, I’ve been introduced to Google Test. It’s so much more full-featured, and paired with Google Mock, it means I don’t need to handroll my own mocks and fakes.

Since UnitTest++ isn’t actively maintained anymore, and Google Test does so much more, I’m switching my development to it.

I do my development on a Linux-based system. I use CMake to manage my builds which allows me to produce a game and port it to Windows easily.

It took me an hour to switch a project over to Google Test. Actually, it took mere minutes to change the code:

TEST_FIXTURE(ParticleFixture, ParticleInitializedWithPositionAndImpulse)
{
CHECK(particle.isAlive());
CHECK(initializedPosition == particle.position);
CHECK(impulse == particle.velocity);
CHECK_EQUAL(maxLifeTime, particle.lifeTime);
CHECK_EQUAL(maxLifeTime, particle.maxLifeTime);
}

turned into:

TEST_F(ParticleFixture, ParticleInitializedWithPositionAndImpulse)
{
EXPECT_TRUE(particle.isAlive());
EXPECT_TRUE(initializedPosition == particle.position);
EXPECT_TRUE(impulse == particle.velocity);
EXPECT_EQ(maxLifeTime, particle.lifeTime);
EXPECT_EQ(maxLifeTime, particle.maxLifeTime);
}

What took longer was figuring out how to add Google Test to my project’s structure.

With UnitTest++, I built it once and had a copy that all of my projects could leverage.

Google Test started out allowing you to “make install”, but citing C++’s
One-Definition Rule, the developers say:

we recommend to avoid installing pre-compiled Google Test libraries. Instead, each project should compile Google Test itself such that it can be sure that the same flags are used for both Google Test and the tests.

I spent quite a bit of time seeing if there was an example of how to do it, but build configurations are based on the needs of individual projects and I suppose it is hard to make such recommendations. So I had to figure out how to write the CMake file, and that’s always a painful process of figuring out what abstract implementation detail is provided by CMake to do the specific work you want.

So here’s my solution.

First, I added the gtest-1.7.0 directory to my project’s test directory. I suppose I could take steps to make this more generic and allow for upgrades without requiring me to change more than necessary, but it works, and it can be tweaked.

Second, I changed my CMakeLists.txt file.

INCLUDE_DIRECTORIES (${BUILD_ENV_LIB}/UnitTest++/src/ ${PROJECT_SOURCE_DIR}/source/game ${PROJECT_BINARY_DIR}/source/game ${PROJECT_SOURCE_DIR}/source/tests/Mocks)
ADD_EXECUTABLE (Test${GB_PROJECT_NAME}-bin ${TEST_SOURCES})
TARGET_LINK_LIBRARIES (Test${GB_PROJECT_NAME}-bin ${GB_PROJECT_NAME}-lib ${BUILD_ENV_LIB}/UnitTest++/libUnitTest++.a) # ${SDL_LIBRARY} ${SDLIMAGE_LIBRARY} ${SDLMIXER_LIBRARY} ${SDLTTF_LIBRARY})
# Run the test executable.
EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/RunTest.sh ${PROJECT_BINARY_DIR})
EXECUTE_PROCESS(COMMAND chmod +x ${PROJECT_BINARY_DIR}/RunTest.sh)
ADD_CUSTOM_COMMAND(TARGET Test${GB_PROJECT_NAME}-bin POST_BUILD COMMAND ${PROJECT_BINARY_DIR}/RunTest.sh ARGS ${PROJECT_BINARY_DIR}/Test${GB_PROJECT_NAME}-bin VERBATIM)

became


ADD_SUBDIRECTORY (gtest-1.7.0)
enable_testing()
INCLUDE_DIRECTORIES (${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/source/game ${PROJECT_BINARY_DIR}/source/game ${PROJECT_SOURCE_DIR}/source/tests/Mocks)
TARGET_LINK_LIBRARIES (Test${GB_PROJECT_NAME}-bin ${GB_PROJECT_NAME}-lib gtest gtest_main) # ${SDL_LIBRARY} ${SDLIMAGE_LIBRARY} ${SDLMIXER_LIBRARY} ${SDLTTF_LIBRARY})
ADD_TEST( Test${GB_PROJECT_NAME}-bin Test${GB_PROJECT_NAME}-bin )
ADD_CUSTOM_COMMAND(TARGET Test${GB_PROJECT_NAME}-bin POST_BUILD COMMAND ${PROJECT_BINARY_DIR}/Test${GB_PROJECT_NAME}-bin)

I used to have my own script run the tests because UnitTest++ didn’t do color-coding. I wanted to see red on failure and green on success. Binaries created using Google Test has red-green colors built-in so I could get rid of my RunTest.sh script.

I’ll be honest, though, I’m not sure what ADD_TEST() is providing. I kept seeing it recommended in the blog posts I could find out there, but as far as I can tell, no one says “I want to run my Google Test tests immediately after a build”.

Supposedly it adds a “test” target to your Makefile, but it seems to be broken. Hence, the ADD_CUSTOM_COMMAND() to actually run the command. I wish the official Google documents would say, “If you want to run your tests as part of the build instead of having to explicitly ask for it, do this.” Instead, I had to cobble together bits and pieces of information from a variety of sources.

So I hope this post helps you if you’re trying to integrate Google Test into your project. And if you see anything I’m doing that can be improved upon, please let me know. It seems project structure and CMake is a dark art to me, and I’m sure there is some workflow improvement I’m missing out on.