GoogleTest — often shortened to GTest — is the most widely used C++ unit testing framework in the world. It powers the test suites of Chromium, LLVM, Protocol Buffers and countless embedded and server codebases, and it ships with a companion mocking library, GoogleMock, in the same repository. If you write C++ and you have not yet picked a test framework, GoogleTest is the safe, well-documented default.
This tutorial takes you from nothing to a working suite. You'll add GoogleTest to a project with CMake, write your first TEST, learn the assertion macros, share setup across tests with fixtures, run the same logic over many inputs with parameterized tests, isolate dependencies with GoogleMock, and finally run everything and measure how much of your code the tests really touched. Every snippet is small enough to type out and compiles conceptually as shown.
What is GoogleTest?
GoogleTest is an xUnit-style testing framework for C++. If you've used JUnit in Java or pytest in Python, the model will feel familiar: you write small, independent test functions, the framework discovers and runs them, and it reports pass/fail with rich diagnostics on failure. There is no separate test runner to register your tests with — the macros do that for you.
Practically, GoogleTest is two things:
- A header you include (
<gtest/gtest.h>) that gives you theTESTmacros, assertions and fixtures. - A library you link (
gtestplusgtest_main, which provides a ready-mademain()).
Bundled alongside it is GoogleMock (the gmock target and <gmock/gmock.h> header), which lets you generate mock implementations of interfaces and set expectations on how they're called. Because they live in one repository and build together, adding GoogleTest gives you mocking for free.
Installing GoogleTest with CMake
The cleanest way to add GoogleTest to a modern C++ project is CMake's FetchContent module. It downloads a pinned version of GoogleTest at configure time and builds it as part of your tree — no system-wide install, no version drift between machines. Create a CMakeLists.txt like this:
cmake_minimum_required(VERSION 3.14) project(MyApp LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # --- Pull in GoogleTest (and GoogleMock) --- include(FetchContent) FetchContent_Declare( googletest URL https://github.com/google/googletest/archive/refs/tags/v1.15.2.zip ) FetchContent_MakeAvailable(googletest) enable_testing() # --- Code under test --- add_library(calc src/calc.cpp) target_include_directories(calc PUBLIC include) # --- Test executable --- add_executable(calc_tests tests/calc_test.cpp) target_link_libraries(calc_tests PRIVATE calc GTest::gtest_main GTest::gmock) include(GoogleTest) gtest_discover_tests(calc_tests)
Linking GTest::gtest_main means you don't have to write your own main().
Configure and build with the usual two commands. gtest_discover_tests registers every test with CTest so they run individually:
$ cmake -S . -B build $ cmake --build build ✓ built target calc ✓ built target calc_tests
Writing your first test
Let's give ourselves something to test. Suppose calc.h declares a tiny function:
// Returns the sum of two integers. int add(int a, int b);
A GoogleTest test is written with the TEST macro, which takes a test suite name and a test name: TEST(SuiteName, TestName). Both are plain identifiers, not strings, and the body is just C++:
#include <gtest/gtest.h> #include "calc.h" TEST(AddTest, HandlesPositiveInput) { EXPECT_EQ(add(2, 3), 5); } TEST(AddTest, HandlesNegativeInput) { EXPECT_EQ(add(-4, 1), -3); }
That's a complete, runnable test file. Each TEST is independent — GoogleTest runs them in isolation and a failure in one never stops the others. When you build and run the executable, you get clear, colorized output telling you which tests ran and passed.
Assertions: ASSERT vs EXPECT
Assertions are how a test states what it expects. GoogleTest gives you two families that differ in one important way:
EXPECT_*reports a failure but continues running the rest of the test. Use it for most checks, so a single run surfaces every problem.ASSERT_*reports a failure and aborts the current test immediately. Use it when continuing makes no sense — for example, after checking a pointer is non-null before you dereference it.
Both families share the same comparison vocabulary. The common ones:
TEST(Assertions, Vocabulary) { EXPECT_EQ(add(2, 2), 4); // equal EXPECT_NE(add(2, 2), 5); // not equal EXPECT_TRUE(add(1, 1) > 0); // boolean true EXPECT_FALSE(add(0, 0) != 0); // boolean false EXPECT_NEAR(3.14159, 3.14, 0.01); // floats within tolerance EXPECT_STREQ("hi", "hi"); // C-string contents equal int* p = make_thing(); ASSERT_NE(p, nullptr); // stop here if null EXPECT_EQ(*p, 42); // safe to dereference now }
Use EXPECT_NEAR for floating-point — never EXPECT_EQ on double, since rounding makes exact equality unreliable. And reach for EXPECT_STREQ when comparing C-style char* strings, because EXPECT_EQ on raw pointers compares addresses, not characters.
Reach for EXPECT_* by default — you want every failure in one run. Switch to ASSERT_* only when a failed check would make the rest of the test crash or produce meaningless results (null pointers, empty containers, failed setup).
Test fixtures with TEST_F
When several tests need the same setup — a database handle, a populated object, a temp directory — copying that setup into each TEST gets repetitive and error-prone. A fixture solves this. You write a class deriving from ::testing::Test, put the shared state in it, and GoogleTest creates a fresh instance for every test so they never bleed into one another.
Override SetUp() to run before each test and TearDown() to run after. Then write tests with TEST_F (the F is for fixture), passing the fixture class name as the first argument:
class StackTest : public ::testing::Test { protected: void SetUp() override { stack_.push(1); stack_.push(2); // runs before EVERY test below } // void TearDown() override { ... } // optional cleanup std::stack<int> stack_; }; TEST_F(StackTest, StartsWithTwoItems) { EXPECT_EQ(stack_.size(), 2u); } TEST_F(StackTest, PopReturnsLastPushed) { EXPECT_EQ(stack_.top(), 2); stack_.pop(); EXPECT_EQ(stack_.top(), 1); }
Because each TEST_F gets its own StackTest instance, the pop() in the second test cannot affect the first. That isolation is what makes a test suite trustworthy.
Parameterized tests with TEST_P
Sometimes you want to run the same logic against many inputs without copy-pasting a test for each. Parameterized tests do exactly that. You derive a fixture from ::testing::TestWithParam<T>, read the current value with GetParam(), write the body once with TEST_P, and feed in the values with INSTANTIATE_TEST_SUITE_P:
// Function under test: bool is_even(int n); class IsEvenTest : public ::testing::TestWithParam<int> {}; TEST_P(IsEvenTest, ReturnsTrueForEvenNumbers) { int value = GetParam(); EXPECT_TRUE(is_even(value)); } INSTANTIATE_TEST_SUITE_P( EvenSamples, // instantiation name IsEvenTest, // the fixture ::testing::Values(0, 2, 8, 100, -6));
GoogleTest expands that into one named test instance per value, so a single failure tells you exactly which input broke. Beyond Values, you can use Range, ValuesIn (to read from a container) and Combine (for the cartesian product of several parameter sets) — handy for boundary and table-driven testing.
Mocking with GoogleMock
Real code talks to things that are slow, non-deterministic or unavailable in a test — networks, clocks, hardware. GoogleMock lets you replace such a dependency with a mock that you fully control. Define mock methods with the MOCK_METHOD macro, then state expectations with EXPECT_CALL.
Say your code depends on an abstract Database interface. You mock it, set up what its calls should return, and verify it was used correctly:
#include <gmock/gmock.h> using ::testing::Return; using ::testing::_; class MockDatabase : public Database { public: MOCK_METHOD(std::string, getName, (int id), (override)); MOCK_METHOD(bool, save, (const User& u), (override)); }; TEST(UserServiceTest, GreetsByName) { MockDatabase db; EXPECT_CALL(db, getName(7)) // expect getName(7)... .Times(1) // ...exactly once... .WillOnce(Return("Ada")); // ...returning "Ada" UserService service(&db); EXPECT_EQ(service.greet(7), "Hello, Ada"); }
The _ token is a matcher meaning "any value." GoogleMock has a rich matcher library — Eq, Gt, HasSubstr, ElementsAre and many more — for expressing precisely which arguments you expect. If the expectations you set aren't met by the time the mock is destroyed, the test fails automatically.
Running tests and measuring coverage
With CTest registration in place, running the whole suite is one command. Internally, GoogleTest's main() simply calls RUN_ALL_TESTS(), which executes every registered test and returns non-zero if any failed:
$ ctest --test-dir build --output-on-failure ✓ AddTest.HandlesPositiveInput ✓ StackTest.PopReturnsLastPushed ✓ IsEvenTest/EvenSamples.ReturnsTrueForEvenNumbers/3 ✓ UserServiceTest.GreetsByName 100% tests passed, 0 tests failed out of 19
Here's the catch every beginner should internalize early: green tests do not prove your tests are good. A passing suite only tells you the assertions you wrote held. It says nothing about the branches, conditions and decisions your tests never reached. The way to see that gap is to measure code coverage — and not just statement coverage, but branch, condition and, for safety-critical work, MC/DC.
You can measure coverage of a GoogleTest run without changing a single source file. RKTracer auto-detects your compiler and instruments during the build when you prefix your normal build command, then reports against the run produced by CTest:
# Prefix your normal build — no source edits, compiler auto-detected $ rktracer cmake --build build compiler: g++ 13.2 (host) ✓ instrumented calc, calc_tests — source unmodified $ ctest --test-dir build # run your GoogleTest suite as usual $ rkresults --report html ✓ Statement 100% ✓ Decision 92% ✓ Condition 81% (3 conditions never reached)
That report is the difference between "the tests pass" and "the tests exercise the code." Where RKTracer finds logic your suite never touched, its AI test generation proposes the additional GoogleTest cases — including the boundary inputs — needed to close those gaps, emitting results as rkresults HTML or XML for your CI.
What to remember from this tutorial
TEST(Suite, Name)for plain tests,TEST_Ffor shared fixtures,TEST_Pfor parameterized runs.EXPECT_*continues on failure;ASSERT_*aborts the test — default to EXPECT.- GoogleMock (
MOCK_METHOD+EXPECT_CALL) isolates the unit under test from slow or external dependencies. - A green suite is necessary but not sufficient — measure coverage to find the logic your tests never reached.
Next steps
You now have the full arc: install with CMake, write a TEST, assert with the right macro, share setup with fixtures, sweep inputs with parameterized tests, isolate dependencies with GoogleMock, and run the lot under CTest. That's enough to write a real, maintainable GoogleTest suite for almost any C++ project.
The natural next move is to close the loop on quality. Wire your suite into CI so it runs on every commit, add coverage measurement so regressions in tested-ness show up as clearly as failing tests, and let coverage point you at the branches still waiting for a test. Green is step one; the gaps are where the bugs hide.