Diferentes comprobaciones de Catch2 en diferentes entradas.
Estoy tratando de probar un código que requiere un poco de configuración para usarlo, y me gustaría evitar repetir los pasos de configuración. Los pasos de configuración dependen del input, pero los resultados podrían ser significativamente diferentes según los inputs exactos. ¿Existe una buena forma de configurar un caso de prueba catch2 para esto?
A modo de ejemplo, consideremos un objeto muy básico que podría querer probar:
“`c++
include <cmath>
struct SquareRoot {
double n;
double root() { return std::sqrt(n); }
};
<pre><code><br />Si quisiéramos escribir algunas pruebas para esto, "positivo" y "negativo" son obvios para verificar ("cero" sería el tercero). Para ambos casos, necesitamos crear un objeto que depende del input, y luego llamar a la función, pero las comprobaciones reales son muy diferentes.
“`c++
include <catch2 catch.hpp=””>
TEST_CASE(“SquareRoot”) {
SECTION(“positive”) {
double n = 4.0;
SquareRoot sqrt{n};
double result = sqrt.root();
REQUIRE(result == 2.0);
}
SECTION(“negative”) {
double n = -4.0;
SquareRoot sqrt{n};
double result = sqrt.root();
REQUIRE(std::isnan(result));
}
}
Podría imaginar generar el input con GENERATE()
, pero luego necesitas alguna forma de decidir qué comprobaciones ejecutar realmente después.
c++
TEST_CASE("SquareRoot") {
double n = GENERATE(4.0, -4.0);
SquareRoot sqrt{n};
double result = sqrt.root();
// ¿Qué REQUIRE debo ejecutar aquí?
}
En el sistema real, el sistema de objetos es más complejo. Si la configuración tiene más de un par de líneas, he tenido éxito dividiéndola en una función separada, pero necesita repetirse en cada test. Del mismo modo, a menudo hay más de una comprobación en el resultado (por ejemplo, podríamos verificar errno
en el caso negativo aquí).
davy.ai
Una forma de evitar repetir los pasos de configuración en las pruebas de Catch2 es utilizar un fixture. Un fixture te permite definir un código de configuración común que se ejecutará antes y después de cada caso de prueba individual. Al utilizar un fixture, puedes definir tu objeto de prueba como una variable miembro y reutilizarlo en diferentes casos de prueba con diferentes parámetros de entrada sin tener que repetir el código de configuración cada vez.
Aquí hay un ejemplo de cómo usar un fixture para probar la clase
SquareRoot
:“`c++
#include
#include
struct SquareRootFixture {
SquareRoot sqrt;
// Define el constructor del fixture que toma el parámetro de entrada
SquareRootFixture(double n) : sqrt{n} {}
};
TEST_CASE(“SquareRoot”, “[square_root]”) {
// Utiliza el fixture en una SECTION
SECTION(“positivo”) {
// Pasa el parámetro de entrada al constructor del fixture
SquareRootFixture fixture{4.0};
double resultado = fixture.sqrt.root();
REQUIRE(resultado == 2.0);
}
SECTION(“negativo”) {
SquareRootFixture fixture{-4.0};
double resultado = fixture.sqrt.root();
REQUIRE(std::isnan(resultado));
}
}
“`
En este ejemplo, la estructura
SquareRootFixture
define una variable miembrosqrt
de tipoSquareRoot
. El constructor del fixture toma el parámetro de entradan
e inicializa el objetosqrt
con él. ElSquareRootFixture
se puede utilizar en unaSECTION
de Catch2 para definir un caso de prueba único, que utiliza el objetosqrt
para realizar la prueba. El parámetro de entrada se puede pasar al constructor delSquareRootFixture
en cadaSECTION
, lo que te permite reutilizar el fixture para diferentes valores de entrada.Al utilizar fixtures, puedes reutilizar fácilmente el código de configuración en diferentes casos de prueba y evitar repetir los mismos pasos de configuración, lo que hace que tus pruebas sean más concisas y mantenibles.