

Introduction:
In this article, we will learn how to implement unit testing using the CMake build system with the Google Test framework. Compared to the previous configuration with Catch2, the Google Test framework is not just a header file; it is a library that includes two files that need to be built and linked. We can place them together with our code project, but to keep the project lightweight, we will choose to download a well-defined Google Test during configuration, then build the framework and link it. We will use the newer FetchContent module (available from CMake version 3.11). Related usage will be covered in subsequent notes.
Additionally, we will select a testing framework (currently Google Test is more popular) after completing the relevant tests and write a small project to practice and familiarize ourselves with as many features of the framework as possible.

✦
Project Structure
✦
NOTE
main.cpp, sum_integers.cpp, and sum_integers.hpp remain the same as in the previous content, and we will make relevant modifications to test.cpp.
.
├── CMakeLists.txt
├── main.cpp
├── sum_integers.cpp
├── sum_integers.h
└── test.cpp
Project address:
https://gitee.com/jiangli01/tutorials/tree/master/cmake-tutorial/chapter4/03
✦
CMakeLists.txt
✦
cmake_minimum_required(VERSION 3.11 FATAL_ERROR)
project(test_gtest LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
add_library(sum_integers sum_integers.cpp)
add_executable(sum_up main.cpp)
target_link_libraries(sum_up sum_integers)
option(ENABLE_UNIT_TESTS "Enable unit tests" ON)
message(STATUS "Enable testing: ${ENABLE_UNIT_TESTS}")
if(ENABLE_UNIT_TESTS)
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://gitcode.net/mirrors/google/googletest.git
GIT_TAG release-1.8.0
)
FetchContent_GetProperties(googletest)
if(NOT googletest_POPULATED)
FetchContent_Populate(googletest)
# Prevent GoogleTest from overriding our compiler/linker options
# when building with Visual Studio
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# Prevent GoogleTest from using PThreads
set(gtest_disable_pthreads ON CACHE BOOL "" FORCE)
# adds the targets: gtest, gtest_main, gmock, gmock_main
add_subdirectory(
${googletest_SOURCE_DIR}
${googletest_BINARY_DIR}
)
# Silence std::tr1 warning on MSVC
if(MSVC)
foreach(_tgt gtest gtest_main gmock gmock_main)
target_compile_definitions(${_tgt}
PRIVATE
"_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING"
)
endforeach()
endif()
endif()
add_executable(cpp_test "")
target_sources(cpp_test
PRIVATE
test.cpp
)
target_link_libraries(cpp_test
PRIVATE
sum_integers
gtest_main
)
enable_testing()
add_test(
NAME google_test
COMMAND $<TARGET_FILE:cpp_test>
)
endif()
Note: The FetchContent module can only be used from CMake version 3.11 onwards.
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
This tells CMake to automatically export all symbols (functions, variables, classes, etc.) from shared libraries (DLL) on the Windows platform.
When this option is set to ON, CMake will automatically insert export directives in the library’s code to ensure they can be linked externally. This is particularly important on Windows as explicit export declarations are required for symbols to be accessed from outside the DLL.
However, enabling this option may lead to larger binary files and may inadvertently expose symbols. If multiple libraries are linked, it may also cause symbol conflicts. Therefore, while it simplifies symbol export, careful consideration of its impact and whether it is suitable for your project is necessary.
option(ENABLE_UNIT_TESTS "Enable unit tests" ON)
message(STATUS "Enable testing: ${ENABLE_UNIT_TESTS}")
if(ENABLE_UNIT_TESTS)
# all the remaining CMake code will be placed here
endif()
Check ENABLE_UNIT_TESTS. By default, it is set to ON, but sometimes it needs to be set to OFF to allow the use of Google Test without a network connection.
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://gitcode.net/mirrors/google/googletest.git
GIT_TAG release-1.8.0
)
The FetchContent module is used to download and integrate the Google Test library (googletest).
-
include(FetchContent): Used to include theFetchContentmodule, which allows fetching external dependencies in the project. -
FetchContent_Declare(googletest ...): Uses theFetchContent_Declaremacro to declare the external dependency to be fetched. In this case, it declares an external dependency namedgoogletest. -
GIT_REPOSITORY: This specifies theURLof theGitrepository used to fetch the library. -
GIT_TAG: This is a specific tag or branch in theGitrepository that specifies the version of the library to be fetched. Here, it specifies the version of theGoogle Testlibrary asrelease-1.8.0.
With this code, when building the project, CMake will attempt to download and integrate the Google Test library so that unit testing can be performed in the project. Note that in actual projects, it may also be necessary to link the Google Test library in the test targets and set up test cases, etc.
if(NOT googletest_POPULATED)
FetchContent_Populate(googletest)
# Prevent GoogleTest from overriding our compiler/linker options
# when building with Visual Studio
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# Prevent GoogleTest from using PThreads
set(gtest_disable_pthreads ON CACHE BOOL "" FORCE)
# adds the targets: gtest, gtest_main, gmock, gmock_main
add_subdirectory(
${googletest_SOURCE_DIR}
${googletest_BINARY_DIR}
)
# Silence std::tr1 warning on MSVC
if(MSVC)
foreach(_tgt gtest gtest_main gmock gmock_main)
target_compile_definitions(${_tgt}
PRIVATE
"_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING"
)
endforeach()
endif()
endif()
-
if(NOT googletest_POPULATED): Checks if theGoogle Testlibrary has already been fetched and integrated. Ifgoogletest_POPULATEDis not defined, the code block will be executed. -
FetchContent_Populate(googletest): Fills the downloadedGoogle Testlibrary content into the specified directory for subsequent building and integration. -
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE): ForcesGoogle Testto use the shared runtime (C Runtime) library when building withVisual Studio. This can avoid linking errors during the build. -
set(gtest_disable_pthreads ON CACHE BOOL "" FORCE): DisablesGoogle Test‘s use ofpthreads. This may be necessary in some environments, such as platforms withoutpthreadssupport. -
add_subdirectory(...): Adds theGoogle Testlibrary to the project. It will be built in the specified source and binary directories. -
For
Microsoft Visual Studio (MSVC), during the build of theGoogle Testlibrary, macro definitions are added to thegtest,gtest_main,gmock, andgmock_maintargets to eliminate warnings underMSVC.
✦
Related Source Code
✦
test.cpp
#include "sum_integers.h"
#include "gtest/gtest.h"
#include <vector>
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
TEST(example, sum_zero) {
auto integers = {1, -1, 2, -2, 3, -3};
auto result = sum_integers(integers);
ASSERT_EQ(result, 0);
}
TEST(example, sum_five) {
auto integers = {1, 2, 3, 4, 5};
auto result = sum_integers(integers);
ASSERT_EQ(result, 15);
}
✦
Output
✦
mkdir build
cd build
cmake ..
ctest
Test project /home/jiangli/repo/tutorials/cmake-tutorial/chapter4/03/build
Start 1: google_test
1/1 Test #1: google_test ...................... Passed 0.00 sec
100% tests passed, 0 tests failed out of 1
Total Test time (real) = 0.01 sec
./cpp_test
[==========] Running 2 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 2 tests from example
[ RUN ] example.sum_zero
[ OK ] example.sum_zero (0 ms)
[ RUN ] example.sum_five
[ OK ] example.sum_five (0 ms)
[----------] 2 tests from example (0 ms total)
[----------] Global test environment tear-down
[==========] 2 tests from 1 test case ran. (0 ms total)
[ PASSED ] 2 tests.
Finally, I wish everyone to become stronger!!!

