C++: Unit Testing

Last updated: 2026-08-26

In lesson 49, we learned about performance optimization.

Now, we'll learn about unit testing — the key skill for ensuring code quality.

Writing code without testing is like cooking without tasting.


1. Unit Testing Overview

(1) 1.1 What Is Unit Testing?

Unit testing involves testing the smallest testable units (functions, classes).

Advantages:


(2) 1.2 Choosing a Test Framework

Framework Description
Google Test Made by Google, most popular
Catch2 Single header file, simple to use
Boost.Test Part of the Boost libraries
Doctest Similar to Catch2, faster

Recommendation: Google Test (full-featured) or Catch2 (simple)



2. Getting Started with Google Test

(1) 2.1 Installing Google Test

Linux:

BASH
sudo apt-get install libgtest-dev

Windows: Use vcpkg or compile from source.


(2) 2.2 Your First Test

Example: Testing an add function with Google Test (Difficulty ⭐)

▶ Example 2: Code example (Difficulty ⭐)

TEXT 📖 Display only
#include <gtest/gtest.h>

int add(int a, int b) {
 return a + b;
}

TEST(AddTest, Positive) {
 EXPECT_EQ(add(2, 3), 5);
}

TEST(AddTest, Negative) {
 EXPECT_EQ(add(-2, -3), -5);
}

int main(int argc, char** argv) {
 ::testing::InitGoogleTest(&argc, argv);
 return RUN_ALL_TESTS();
}

Output:

TEXT 📖 Display only
[==========] Running 2 tests from 1 test suite.
[  PASSED  ] 2 tests.

Run result:

TEXT 📖 Display only
[==========] Running 2 tests from 1 test suite.
[ PASSED ] 2 tests.


3. Assertion Macros

(1) 3.1 ASSERT vs EXPECT

Macro Behavior on Failure
ASSERT_* Stops the current test
EXPECT_* Continues running

Recommendation: Use EXPECT_* (you can see more failures)


(2) 3.2 Common Assertions

Assertion Description
EXPECT_EQ(a, b) a == b
EXPECT_NE(a, b) a != b
EXPECT_LT(a, b) a < b
EXPECT_GT(a, b) a > b
EXPECT_TRUE(cond) cond is true
EXPECT_FALSE(cond) cond is false
EXPECT_THROW(statement, exception_type) Expects an exception to be thrown


4. Test Fixtures

(1) 4.1 Why Do We Need Fixtures?

Problem: Multiple tests need the same initialization code.

Solution: Test fixtures (inherit from testing::Test)


(2) 4.2 Example: Testing a queue with fixtures (Difficulty ⭐⭐)

CPP
#include <gtest/gtest.h>
#include <queue>

class QueueTest : public testing::Test {
protected:
 void SetUp() override {
 q.push(1);
 q.push(2);
 q.push(3);
 }
 
 void TearDown() override {
 // Cleanup (if needed)
 }
 
 std::queue<int> q;
};

TEST_F(QueueTest, Size) {
 EXPECT_EQ(q.size(), 3);
}

TEST_F(QueueTest, Front) {
 EXPECT_EQ(q.front(), 1);
}

int main(int argc, char** argv) {
 ::testing::InitGoogleTest(&argc, argv);
 return RUN_ALL_TESTS();
}

Output:

TEXT 📖 Display only
(Program output)


5. Test-Driven Development (TDD)

(1) 5.1 What Is TDD?

TDD (Test-Driven Development) means writing tests first, then writing code.

Process:

  1. Write a test (it fails)
  2. Write the code (it passes)
  3. Refactor

(2) 5.2 Example: TDD for a Stack (Difficulty ⭐⭐⭐)

TEXT 📖 Display only
// 1. Write the test first
TEST(StackTest, PushAndPop) {
 Stackint s;
 s.push(42);
 EXPECT_EQ(s.pop(), 42);
}

// 2. Then write the code
template<typename T>
class Stack {
 std::vectorT data;
public:
 void push(const T& x) { data.push_back(x); }
 T pop() { T x = data.back(); data.pop_back(); return x; }
};

Output:

TEXT 📖 Display only
(Program output)


6. Practice: Testing a Student Class

▶ Example 1: Complete test (Difficulty ⭐⭐⭐)

CPP
#include <gtest/gtest.h>
#include <string>

class Student {
 std::string name;
 int age;
 
public:
 Student(const std::string& name, int age) : name(name), age(age) {}
 
 std::string getName() const { return name; }
 int getAge() const { return age; }
};

TEST(StudentTest, Constructor) {
 Student s("Zhang San", 20);
 EXPECT_EQ(s.getName(), "Zhang San");
 EXPECT_EQ(s.getAge(), 20);
}

int main(int argc, char** argv) {
 ::testing::InitGoogleTest(&argc, argv);
 return RUN_ALL_TESTS();
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
(Program output)

▶ Example 3: Simple unit test (Difficulty ⭐)

CPP
#include <iostream>
#include <cassert>

// Functions being tested
int multiply(int a, int b) {
    return a * b;
}

bool isPositive(int n) {
    return n > 0;
}

int main() {
    // Test multiply
    assert(multiply(2, 3) == 6);
    assert(multiply(-2, 3) == -6);
    assert(multiply(0, 5) == 0);
    std::cout << "multiply Test passed" << std::endl;

    // Test isPositive
    assert(isPositive(5) == true);
    assert(isPositive(-1) == false);
    assert(isPositive(0) == false);
    std::cout << "isPositive Test passed" << std::endl;

    std::cout << "All tests passed!" << std::endl;
    return 0;
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
multiply Test passed
isPositive Test passed
All tests passed!

❓ FAQ

Q: Can unit testing find all bugs? A: No. Unit tests can only find known types of errors. You also need integration testing and system testing.


Q Should test code be shipped with production code?
A No. Test code is typically only used during development.

Q How do I test private functions?
A - Method 1: Test the public interface (indirect testing) - Method 2: Use FRIEND_TEST to expose private members - Method 3: Refactor by extracting private functions into a separate class

📖 Summary

Key Point Summary
Unit testing Test the smallest units
Google Test Most popular C++ test framework
Assertion macros EXPECT_* and ASSERT_*
Test fixtures Share initialization code
TDD Write tests first, then code

📝 Exercises

  1. Basic (Difficulty ⭐): Write an add(a, b) function and create 3 test cases with Google Test: adding positive numbers, adding negative numbers, adding zeros.

  2. Intermediate (Difficulty ⭐⭐): Write an isPalindrome function that checks if a string is a palindrome. Write at least 5 test cases covering normal, boundary, and special inputs.

  3. Challenge (Difficulty ⭐⭐⭐): Write complete unit tests for a "Bank Account" class (with deposit/withdraw/getBalance methods). Test normal deposits/withdrawals, overdraft rejection, and thread safety (if applicable).



Next lesson: Practice — Contact Management System (#51)

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏