c++ unit-testing boost boost-unit-test-framework

c++ - ¿Cómo comparar vectores con Boost.Test?



unit-testing boost-unit-test-framework (5)

Estoy usando Boost Test para probar un poco el código C ++.

Tengo un vector de valores que necesito comparar con los resultados esperados, pero no quiero verificar manualmente los valores en un bucle:

BOOST_REQUIRE_EQUAL(values.size(), expected.size()); for( int i = 0; i < size; ++i ) { BOOST_CHECK_EQUAL(values[i], expected[i]); }

El problema principal es que la comprobación de bucle no imprime el índice, por lo que requiere una búsqueda para encontrar la falta de coincidencia.

Podría usar std::equal o std::mismatch en los dos vectores, pero eso también requerirá una gran cantidad de repetición.

¿Hay una manera más limpia de hacer esto?


¿Qué hay de BOOST_CHECK_EQUAL_COLLECTIONS ?

BOOST_AUTO_TEST_CASE( test ) { int col1 [] = { 1, 2, 3, 4, 5, 6, 7 }; int col2 [] = { 1, 2, 4, 4, 5, 7, 7 }; BOOST_CHECK_EQUAL_COLLECTIONS( col1, col1+7, col2, col2+7 ); }

ejemplo

Ejecutando 1 caso de prueba ...

test.cpp (11): error en "prueba": comprobación {col1, col1 + 7} == {col2, col2 + 7} falló.

No coinciden en una posición 2: 3! = 4

Desajuste en una posición 5: 6! = 7

* 1 fallo detectado en la prueba "ejemplo"


Desde Boost 1.59 es mucho más fácil comparar instancias de std::vector . Consulte esta documentación para la versión 1.63 (que es casi igual a este respecto a 1.59).

Por ejemplo, si ha declarado std::vector<int> a, b; puedes escribir

BOOST_TEST(a == b);

Para obtener una comparación muy básica. La desventaja de esto es que en caso de falla, Boost solo te dice que a y b no son lo mismo. Pero obtienes más información al comparar elementos, lo que es posible de una manera elegante

BOOST_TEST(a == b, boost::test_tools::per_element() );

O si quieres una comparación lexicográfica puedes hacerlo.

BOOST_TEST(a <= b, boost::test_tools::lexicographic() );


Puede usar BOOST_REQUIRE_EQUAL_COLLECTIONS con std::vector<T> , pero tiene que enseñar a Boost. Pruebe cómo imprimir un std::vector cuando tiene un vector de vectores o un mapa cuyos valores son vectores. Cuando tenga un mapa, debe enseñarle a Boost.Test cómo imprimir std::pair . Como no puede cambiar la definición de std::vector o std::pair , debe hacer esto de tal manera que Boost.Test usará el operador de inserción de flujo que defina sin ser parte de la definición de clase de std::vector . Además, esta técnica es útil si no desea agregar operadores de inserción de secuencias a su sistema bajo prueba solo para que Boost.Test esté contento.

Aquí está la receta para cualquier std::vector :

namespace boost { // teach Boost.Test how to print std::vector template <typename T> inline wrap_stringstream& operator<<(wrap_stringstream& wrapped, std::vector<T> const& item) { wrapped << ''[''; bool first = true; for (auto const& element : item) { wrapped << (!first ? "," : "") << element; first = false; } return wrapped << '']''; } }

Esto da formato a los vectores como [e1,e2,e3,...,eN] para un vector con N elementos y funcionará para cualquier número de vectores anidados, por ejemplo, donde los elementos del vector también son vectores.

Aquí está la receta similar para std::pair :

namespace boost { // teach Boost.Test how to print std::pair template <typename K, typename V> inline wrap_stringstream& operator<<(wrap_stringstream& wrapped, std::pair<const K, V> const& item) { return wrapped << ''<'' << item.first << '','' << item.second << ''>''; } }

BOOST_REQUIRE_EQUAL_COLLECTIONS le indicará el índice de los elementos que no coinciden, así como el contenido de las dos colecciones, asumiendo que las dos colecciones son del mismo tamaño. Si son de diferentes tamaños, eso se considera una falta de coincidencia y se imprimen los diferentes tamaños.


Sin embargo, un poco fuera de tema, cuando a veces uno necesita comparar colecciones de números de punto flotante usando comparación con tolerancia , este fragmento de código puede ser útil:

// Have to make it a macro so that it reports exact line numbers when checks fail. #define CHECK_CLOSE_COLLECTION(aa, bb, tolerance) { / using std::distance; / using std::begin; / using std::end; / auto a = begin(aa), ae = end(aa); / auto b = begin(bb); / BOOST_REQUIRE_EQUAL(distance(a, ae), distance(b, end(bb))); / for(; a != ae; ++a, ++b) { / BOOST_CHECK_CLOSE(*a, *b, tolerance); / } / }

Esto no imprime los índices de matriz de elementos no coincidentes, pero sí imprime los valores no coincidentes con alta precisión, por lo que a menudo son fáciles de encontrar.

Ejemplo de uso:

auto mctr = pad.mctr(); std::cout << "mctr: " << io::as_array(mctr) << ''/n''; auto expected_mctr{122.78731602430344,-13.562000155448914}; CHECK_CLOSE_COLLECTION(mctr, expected_mctr, 0.001);


Utilice BOOST_CHECK_EQUAL_COLLECTIONS . Es una macro en test_tools.hpp que toma dos pares de iteradores:

BOOST_CHECK_EQUAL_COLLECTIONS(values.begin(), values.end(), expected.begin(), expected.end());

Se reportarán los índices y los valores que no coinciden. Si los tamaños no coinciden, también informará eso (y no se quedará sin el final del vector).

Tenga en cuenta que si desea utilizar BOOST_CHECK_EQUAL o BOOST_CHECK_EQUAL_COLLECTIONS con tipos que no son POD, deberá implementar

bool YourType::operator!=(const YourType &rhs) // or OtherType std::ostream &operator<<(std::ostream &os, const YourType &yt)

Para la comparación y registro, respectivamente.
El orden de los iteradores pasados ​​a BOOST_CHECK_EQUAL_COLLECTIONS determina cuál es el RHS y el LHS de la comparación != . El primer rango del iterador será el LHS en las comparaciones.