Pruebas en C++: frameworks y herramientas
La calidad del código en C++ es un factor crítico para la confiabilidad del software. A diferencia de los lenguajes con memoria administrada, los errores en C++ pueden provocar fallos graves, fugas de memoria y comportamiento indefinido. El sistema de pruebas unitarias (unit testing) permite detectar defectos en etapas tempranas, facilita la refactorización y documenta el comportamiento de las funciones. En este artículo, revisaremos tres frameworks populares para pruebas en C++: Google Test, Catch2 y doctest, así como herramientas para su integración en el proceso de desarrollo.
¿Por qué son necesarias las pruebas en C++?
- Seguridad durante la refactorización: las pruebas señalan regresiones al instante.
- Documentación: las pruebas legibles sirven como ejemplos vivos del uso de la API.
- Integración con CI: ejecución automática de pruebas en cada commit.
- Detección de comportamiento indefinido: pruebas con sanitizers (AddressSanitizer, UndefinedBehaviorSanitizer).
1. Google Test (GTest)
El framework más popular de Google. Soporta el estilo xUnit, un rico conjunto de macros de aserciones (assertions), registro automático de pruebas, mocks (a través de Google Mock) y pruebas parametrizadas.
Instalación (a través de 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)Ejemplo de prueba
#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 para definir un caso de prueba.EXPECT_EQ— verificación de igualdad (no fatal).ASSERT_*— verificaciones fatales (interrumpen la prueba si fallan).
2. Catch2
Un framework moderno con énfasis en la legibilidad y la simplicidad. Soporta el estilo BDD (Given-When-Then), secciones (división de pruebas en escenarios anidados) y generación de datos aleatorios. No requiere herencia de clases base.
Instalación (single-header o a través de vcpkg)
# vcpkgvcpkg install catch2
# CMakefind_package(Catch2 REQUIRED)target_link_libraries(my_tests Catch2::Catch2)Ejemplo de prueba
#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— declaración de una prueba con nombre y etiquetas.REQUIRE— verificación fatal.CHECK— verificación no fatal.SECTION— escenario anidado (cada sección se ejecuta desde el estado común).
3. Doctest
Una alternativa ligera y rápida. Inspirado en Catch2, pero se compila de 2 a 5 veces más rápido. Está diseñado para proyectos donde la velocidad de compilación es importante. Soporta archivo de cabecera (header-only), las macros CHECK y REQUIRE, así como la salida en formato XML.
Instalación (he
También en la biblioteca
Puppeteer para JavaScript (Node.js): guía completa con ejemplos
Burn para Rust: guía completa con ejemplos prácticos
ORM para Java: comparación de Hibernate, MyBatis y JPA con ejemplos
Biometric para Kotlin: guía completa con ejemplos prácticos
Validación de datos en Go: revisión de bibliotecas y enfoques