Background
Welcome to 2021. This is my first article for this year and I want to start with a useful tip for C++ unit testing. Unlike other languages, unit testing in C++ has never been as straightforward. However, googletest (also known as “gtest”) has been one of the more well-received testing framework in various organizations, so that’s what I will focus on.
What makes this article slightly different is that unlike the traditional way of defining an entry point for your testing program (ie. a main() function), I will walk through how NOT to do that - how to use googletest with CMake without defining any entry point.
Test case
Let’s suppose that I want to test some function. The standard way to define a test case using gtest is the following:
// Component under test
#include <myproject/maths.h>
// gtest include
#include <gtest/gtest.h>
using namespace ::testing;
TEST(my_function_test, basic) {
// Assume that I want to test if myproject::abs()
// returns the correct absolute value of an integer
ASSERT_EQ(myproject::abs(-100), 100);
}
As you see, I have defined a test case called my_function_test.basic and it tests if abs returns the correct absolute value - nothing exciting.
However, this is just a function - to run our test case, naturally we want to have some entry point just like any program. There’s one way to do it: define a main function somewhere like this:
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
While this works, there’s a neat way to get rid of this main function completely while still being able to run our tests.
gtest_main
A main function seems out of place being placed in a directory specifically for test cases. Fortunately, Google agrees with this idea and they’ve provided the gtest_main library that gives a basic implementation of main(). It means that we don’t need an explicit entry point in our program.
CMake
It’s simple to use gtest_main with CMake:
file(GLOB_RECURSE SRCS CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
set(target, my_project.t)
add_executable(${target} ${SRCS})
find_package(GTest REQUIRED)
include(GoogleTest)
target_link_libraries(${target} PRIVATE
my_project
gmock
GTest::GTest
GTest::Main
)
gtest_discover_tests(${target})
Or it coule be simpler:
file(GLOB_RECURSE SRCS CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
set(target, my_project.t)
add_executable(${target} ${SRCS})
target_link_libraries(${target} PRIVATE
my_project
gmock
gtest
gtest_main
)
gtest_discover_tests(${target})
After building our project, simply run ctest in the build directory and all test cases will run 😃.