I wanted to get started with GoogleTest, and while searching for information, I came across this solution. I hope it can save you some time in your search.
Prerequisites
- A compatible operating system (e.g. Linux, macOS, Windows).
- A compatible C/C++ compiler
- CMake installed
Set up the project
To get started with GoogleTest, follow these steps to set up your project structure. Below is the folder tree we'll use and a brief explanation of each component:
Folder tree
googletest-boilerplate # Root directory of your project
├── CMakeLists.txt # Top-level CMake configuration file
├── src # Directory for source code
│ ├── CMakeLists.txt # CMake configuration for source files
│ ├── example.c # C source file with implementation code
│ ├── example.h # Header file for example.c
│ └── main.c # Main source file
└── tests # Directory for test code
├── CMakeLists.txt # CMake configuration for test files
├── test_example.cpp # C++ file containing test cases
└── test_main.cpp # C++ file that sets up GoogleTest and runs tests
Let’s start with the top-level CMakeLists.txt
file. This file configures the overall project and includes the subdirectories for source and test files. Here’s what the content will look like:
cmake_minimum_required(VERSION 3.14) # Minimum CMake version required
project(googletest-boilerplate VERSION 0.1.0 LANGUAGES C CXX) # Project name and version, specifying C and C++ languages
# Set the C and C++ standards
set(CMAKE_C_STANDARD 11) # Set C standard to C11
set(CMAKE_C_STANDARD_REQUIRED True) # Ensure the C standard is required
set(CMAKE_CXX_STANDARD 14) # Set C++ standard to C++14
set(CMAKE_CXX_STANDARD_REQUIRED True) # Ensure the C++ standard is required
# Add subdirectories for source and test files
add_subdirectory(src) # Includes the src directory
add_subdirectory(tests) # Includes the tests directory
include(CTest) # Include CTest module for testing support
Followed by tests/CMakeLists.txt
:
include(FetchContent)
# Fetch GoogleTest
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.11.0
)
FetchContent_MakeAvailable(googletest)
# Collect C++ source files recursively
file(GLOB_RECURSE CXX_FILES "${CMAKE_CURRENT_LIST_DIR}/*.cpp")
add_executable(unit_tests ${CXX_FILES})
# Link GoogleTest libraries
target_link_libraries(unit_tests
PRIVATE
gtest_main
${PROJECT_NAME}_lib # Link to the main project library
)
# Include directories (including where GoogleTest is built)
target_include_directories(unit_tests PRIVATE ${gtest_SOURCE_DIR}/include)
# Add include directories for tests to find headers
target_include_directories(unit_tests PRIVATE ${PROJECT_SOURCE_DIR}/src)
# Enable testing and discover tests
# Discover and run tests
include(GoogleTest)
gtest_discover_tests(unit_tests)
Followed by src/CMakeList.txt
:
# Set the source directory to the current directory
set(SRC_DIR ${CMAKE_CURRENT_LIST_DIR})
# Recursively collect all .c and .h files in the source directory
file(GLOB_RECURSE SOURCES ${SRC_DIR}/*.c ${SRC_DIR}/*.h)
# Define the name of the main project library using the project name with a "_lib" suffix
set(MAIN_PROJECT_LIBNAME ${PROJECT_NAME}_lib)
# Create a static library from the collected source files
add_library(${MAIN_PROJECT_LIBNAME} STATIC
${SOURCES}
)
# Add the main executable, specifying 'main.c' as the source file
add_executable(${PROJECT_NAME} main.c)
# Link the main executable with the static library created earlier
target_link_libraries(${PROJECT_NAME} ${MAIN_PROJECT_LIBNAME})
On the CMake side, we're done. Let's quickly take a look at the sources now.
tests/test_main.cpp
#include <gtest/gtest.h> // Include the GoogleTest framework header
// Dummy test
// Define a test case named 'ExampleTest' and a test named 'test'
TEST(ExampleTest, test)
{
EXPECT_EQ(true, true);
}
int main(int argc, char **argv) {
// Initialize the GoogleTest framework with command-line arguments
::testing::InitGoogleTest(&argc, argv);
// Run all the tests that have been defined and return the result
return RUN_ALL_TESTS();
}
Note: In the code below, we can access the functions from example.h
because we included the src directory in the include path by specifying the following line in tests/CMakeLists.txt
(line 24):
target_include_directories(unit_tests PRIVATE ${PROJECT_SOURCE_DIR}/src)
If your project has a more complex directory structure, make sure to include the necessary directories in the include path to ensure proper access to header files.
tests/test_example.cpp
This will be the core test of our example. We'll call the functions inside the src
directory."
#include <gtest/gtest.h>
#include "example.h"
TEST(Example, sumTest)
{
uint32_t a = 10;
uint32_t b = 20;
EXPECT_EQ(a + b, sum(a, b));
}
TEST(Example, squareTest)
{
uint32_t a = 10;
EXPECT_EQ(a * a, square(a));
}
Source code files here below:
src/example.h
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
uint32_t sum(uint32_t a, uint32_t b);
uint32_t square(uint32_t a);
#ifdef __cplusplus
}
#endif
src/example.c
#include "example.h"
uint32_t sum(uint32_t a, uint32_t b)
{
return a + b;
}
uint32_t square(uint32_t a)
{
return a*a;
}
src/main.c
#include <stdio.h>
int main(int argc, char** argv)
{
puts("Hello World!");
return 0;
}
Compilation
To compile the project, follow these steps:
mkdir build
cd build
cmake ..
cmake --build .
Run the test suite
After compiling, you can run the test suite using the following command:
./tests/unit_tests
Upon running the tests, you should see output similar to this:
[==========] Running 3 tests from 2 test suites.
[----------] Global test environment set-up.
[----------] 2 tests from Example
[ RUN ] Example.sumTest
[ OK ] Example.sumTest (0 ms)
[ RUN ] Example.squareTest
[ OK ] Example.squareTest (0 ms)
[----------] 2 tests from Example (0 ms total)
[----------] 1 test from ExampleTest
[ RUN ] ExampleTest.test
[ OK ] ExampleTest.test (0 ms)
[----------] 1 test from ExampleTest (0 ms total)
[----------] Global test environment tear-down
[==========] 3 tests from 2 test suites ran. (0 ms total)
[ PASSED ] 3 tests.
If you see a similar output, congratulations! Your setup is complete and the tests have passed successfully.
GitHub Repository
You can find the full project and source code on GitHub:
Feel free to clone the repository, explore the code, and contribute if you have any improvements or suggestions.
I hope this article has saved you some time searching for this information online.
Happy coding!
Top comments (1)
Since you have
include(CTest)
, I guess you can simply use the commandctest
to run the tests. Otherwise, this line is probably not necessary.Note that using
file(GLOB_RECURSE....
to get the source file of your project is generally considered as a bad practice, because it has several drawbacks. Instead, simply manually list your files by name. It's generally used when you can't manually enumerate the source files (eg: when files are generated and we can't predict their name easily).