Pruebas en C++: visión general de frameworks y herramientas (Google Test, Catch2, doctest)

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Pruebas en C++: frameworks y herramientas



Las pruebas de calidad son una parte esencial del desarrollo en C++. A diferencia de los lenguajes dinámicos, C++ requiere una atención especial a la gestión de memoria, el tiempo de vida de los objetos y el rendimiento. En este artículo, analizaremos los tres frameworks más populares para pruebas unitarias: Google Test, Catch2 y doctest, y también mencionaremos herramientas adicionales.



¿Por qué son necesarias las pruebas en C++?

C++ es un lenguaje con gestión manual de memoria y potente magia de plantillas. Sin pruebas, es fácil cometer:

  • Fugas de memoria y doble liberación
  • Comportamiento indefinido (UB) al trabajar con punteros
  • Errores en la sobrecarga de operadores y constructores de copia
  • Regresiones al refactorizar código heredado

Los frameworks de pruebas automatizan la verificación y ayudan a encontrar problemas rápidamente.



Google Test (gtest)

El framework más común de Google. Soporta todas las funciones principales: macros ASSERT_* y EXPECT_*, pruebas parametrizadas, fixtures (test fixtures), death-tests.



Instalación (mediante CMake FetchContent)

include(FetchContent)FetchContent_Declare(  googletest  GIT_REPOSITORY https://github.com/google/googletest.git  GIT_TAG release-1.14.0)FetchContent_MakeAvailable(googletest)


Ejemplo de prueba simple

#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_EQ(factorial(3), 6);}

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


Fixtures y pruebas parametrizadas

class MathFixture : public ::testing::Test {protected:    void SetUp() override { /* inicialización */ }    void TearDown() override { /* limpieza */ }};

// Prueba parametrizadaclass SumTest : public ::testing::TestWithParam<std::tuple<int, int, int>> {};TEST_P(SumTest, CheckSum) { auto [a, b, expected] = GetParam(); EXPECT_EQ(a + b, expected);}INSTANTIATE_TEST_SUITE_P(SumParams, SumTest, ::testing::Values( std::make_tuple(1, 1, 2), std::make_tuple(0, 0, 0) ));


Ventajas: gran comunidad, integración con CI/CD, macros potentes, soporte para death-tests.
Desventajas: compilación relativamente lenta, gran tamaño del archivo ejecutable.



Catch2

Framework moderno con énfasis en la legibilidad de las pruebas. Utiliza estilo BDD (Behaviour-Driven Development) y soporta secciones (sections).



Instalación (header-only)

Catch2 se distribuye como un único archivo de cabecera. Basta con descargar catch_amalgamated.hpp e incluirlo.



Ejemplo con secciones

#define CATCH_CONFIG_MAIN#include <catch2/catch.hpp>

int divide(int a, int b) { if (b == 0) throw std::invalid_argument("division by zero"); return a / b;}

TEST_CASE("Division tests", "[math]") { SECTION("Normal division") { REQUIRE(divide(10, 2) == 5); } SECTION("Division by zero") { REQUIRE_THROWS_AS(divide(5, 0), std::invalid_argument); }}


Estilo BDD (Given-When-Then)

SCENARIO("Vector push_back operation", "[container]") {    GIVEN("An empty vector") {        std::vector<int> v;        WHEN("We push one element") {            v.push_back(42);            THEN("The size becomes 1") {                REQUIRE(v.size() == 1);            }            AND_THEN("The element is correct") {                REQUIRE(v[0] == 42);                    

Recommendations