Тестирование в C++: фреймворки и инструменты
Качество кода на C++ — критический фактор для надёжности программного обеспечения. В отличие от языков с управляемой памятью, ошибки в C++ могут приводить к серьёзным сбоям, утечкам памяти и неопределённому поведению. Система модульного тестирования (unit-тестирования) позволяет выявлять дефекты на ранних этапах, облегчает рефакторинг и документирует поведение функций. В этой статье мы рассмотрим три популярных фреймворка для тестирования на C++: Google Test, Catch2 и doctest, а также инструменты для их интеграции в процесс разработки.
Зачем нужно тестирование в C++?
- Безопасность при рефакторинге: тесты мгновенно сигнализируют о регрессиях.
- Документация: читаемые тесты служат живыми примерами использования API.
- Интеграция с CI: автоматический прогон тестов при каждом коммите.
- Выявление неопределённого поведения: тесты с санитайзерами (AddressSanitizer, UndefinedBehaviorSanitizer).
1. Google Test (GTest)
Наиболее популярный фреймворк от Google. Поддерживает xUnit-стиль, богатый набор макросов утверждений (assertions), автоматическую регистрацию тестов, моки (через Google Mock) и параметризованные тесты.
Установка (через CMake FetchContent)
# CMakeLists.txt
include(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)
Пример теста
#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()— макрос для определения тестового случая.EXPECT_EQ— проверка равенства (нефатальная).ASSERT_*— фатальные проверки (прерывают тест при провале).
2. Catch2
Современный фреймворк с акцентом на читаемость и простоту. Поддерживает BDD-стиль (Given-When-Then), секции (разделение тестов на вложенные сценарии) и генерацию случайных данных. Не требует наследования от базовых классов.
Установка (single-header или через vcpkg)
# vcpkg
vcpkg install catch2
# CMake
find_package(Catch2 REQUIRED)
target_link_libraries(my_tests Catch2::Catch2)
Пример теста
#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— объявление теста с именем и тегами.REQUIRE— фатальная проверка.CHECK— нефатальная проверка.SECTION— вложенный сценарий (каждая секция запускается из общего состояния).
3. Doctest
Лёгкая и быстрая альтернатива. Вдохновлён Catch2, но компилируется в 2-5 раз быстрее. Предназначен для проектов, где важна скорость сборки. Поддерживает заголовочный файл (header-only), макросы CHECK и REQUIRE, а также вывод в формате XML.
Установка (header-only)
# CMakeLists.txt add_executable(test_doctest test.cpp) target_include_directories(test_doctest PRIVATE /path/to/doctest/headers)Также в библиотеке
Joi для JavaScript (Node.js): полное руководство с примерами
HTTP-клиент для JavaScript (Node.js): топ библиотек для работы с API
Сериализация объектов в Java: полное руководство для начинающих
Машинное обучение на C++: обзор библиотек для разработки
MetricsKit — мониторинг приложений Swift (iOS/macOS)
Рекомендаций