Testing in C++: Frameworks and Tools
Code quality in C++ is a critical factor for software reliability. Unlike languages with managed memory, errors in C++ can lead to serious crashes, memory leaks, and undefined behavior. A unit testing system allows you to detect defects at early stages, facilitates refactoring, and documents function behavior. In this article, we will review three popular frameworks for testing in C++: Google Test, Catch2, and doctest, as well as tools for integrating them into the development process.
Why is testing needed in C++?
- Safety during refactoring: tests instantly signal regressions.
- Documentation: readable tests serve as live examples of API usage.
- Integration with CI: automatic test execution on every commit.
- Detection of undefined behavior: tests with sanitizers (AddressSanitizer, UndefinedBehaviorSanitizer).
1. Google Test (GTest)
The most popular framework from Google. Supports xUnit style, a rich set of assertion macros, automatic test registration, mocks (via Google Mock), and parameterized tests.
Installation (via CMake FetchContent)
# CMakeLists.txtinclude(FetchContent)FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG release-1.12.1)FetchContent_MakeAvailable(googletest)
add_executable(my_tests test.cpp)target_link_libraries(my_tests GTest::gtest_main)Test Example
#include <gtest/gtest.h>
int factorial(int n) { return (n <= 1) ? 1 : n * factorial(n - 1);}
TEST(FactorialTest, HandlesZeroInput) { EXPECT_EQ(factorial(0), 1);}
TEST(FactorialTest, HandlesPositiveInput) { EXPECT_EQ(factorial(5), 120); EXPECT_GT(factorial(3), 5);}
int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS();}TEST()— macro for defining a test case.EXPECT_EQ— equality check (non-fatal).ASSERT_*— fatal checks (abort the test on failure).
2. Catch2
A modern framework with an emphasis on readability and simplicity. Supports BDD style (Given-When-Then), sections (splitting tests into nested scenarios), and random data generation. Does not require inheritance from base classes.
Installation (single-header or via vcpkg)
# vcpkgvcpkg install catch2
# CMakefind_package(Catch2 REQUIRED)target_link_libraries(my_tests Catch2::Catch2)Test Example
#define CATCH_CONFIG_MAIN#include <catch2/catch.hpp>
int add(int a, int b) { return a + b; }
TEST_CASE("Addition works", "[math]") { REQUIRE(add(2, 2) == 4); CHECK(add(-1, 1) == 0);
SECTION("With zero") { REQUIRE(add(0, 5) == 5); }}
TEST_CASE("String concatenation", "[string]") { std::string result = std::string("Hello ") + "World"; CHECK(result == "Hello World");}TEST_CASE— test declaration with name and tags.REQUIRE— fatal check.CHECK— non-fatal check.SECTION— nested scenario (each section runs from a common state).
3. Doctest
A lightweight and fast alternative. Inspired by Catch2, but compiles 2-5 times faster. Designed for projects where build speed is important. Supports header-only, CHECK and REQUIRE macros, as well as XML output.
Installation (he
Also in library
Database Migrations in Kotlin: Overview of Tools and Approaches
Task Scheduler in TypeScript: Complete Guide to Cron Libraries and Timers
Authorization and Authentication in C# (.NET) — Complete Guide
Working with S3 and Cloud Storage in Kotlin: AWS SDK and Ktor S3 Client