2010-10-22 14 views
16

Używam testu Boost do testowania kodu C++.Jak porównać wektory z Boost.Test?

Mam wektor wartości, które muszę porównać z oczekiwanymi rezultatami, ale nie chcę, aby ręcznie sprawdzić wartości w pętli:

BOOST_REQUIRE_EQUAL(values.size(), expected.size()); 

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

Głównym problemem jest to, że nie robi check pętla 't drukowania indeksu, więc wymaga trochę wyszukiwania, aby znaleźć niezgodność.

Mogę użyć std::equal lub std::mismatch na dwóch wektorach, ale będzie to wymagało również wielu elementów.

Czy jest to czystszy sposób?

Odpowiedz

30

Użyj BOOST_CHECK_EQUAL_COLLECTIONS. Jest to makro w test_tools.hpp że trwa dwie pary iteratorów:

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

będzie przekazywać indeksów i wartości, które niedopasowania. Jeśli rozmiary nie są zgodne, to również to zgłosi (i nie będzie po prostu spływać z końca wektora).


Pamiętaj, że jeśli chcesz używać BOOST_CHECK_EQUAL lub BOOST_CHECK_EQUAL_COLLECTIONS z typami non-Pod, trzeba będzie wdrożyć

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

do porównywania i rejestracji, odpowiednio.
Kolejność iteratorów przekazanych do BOOST_CHECK_EQUAL_COLLECTIONS określa, który jest RHS i LHS porównania != - pierwszy zakres iteratora będzie LHS w porównaniach.

+2

to w docs, to tylko dobrze ukryty –

+1

Tak, jestem zajęty edytowaniem mojego wstydu. :) Dziękuję za twoje przykłady w twojej odpowiedzi. – mskfisher

+0

To zbyt nieprzyjemne, aby zmusić system do testowania, aby zaimplementować 'operator! =' I 'operator <<' tylko po to, aby zadowolić Boost.Test, IMO. Ponadto nie można zdefiniować tych funkcji składowych dla 'std :: vector'. Zobacz moją odpowiedź poniżej, aby uzyskać lepsze rozwiązanie. – legalize

10

Co powiecie na ?

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); 
} 

przykład

Running przypadek 1 test ...

test.cpp (11): błąd w "teście": sprawdź {col1, col1 + 7} == {col2 , col2 + 7} nie powiodło się.

Niezgodność w pozycji 2: 3 = 4

Niezgodność w pozycji 5: 6 = 7

* 1 brak wykryte w testowych "Przykład"

9

Trochę poza tematem, gdy czasami trzeba porównać kolekcje liczb zmiennoprzecinkowych za pomocą comparison with tolerance, ten fragment może być przydatny:

// 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); \ 
    } \ 
} 

To nie drukuje indeksów niedopasowanych elementów, ale drukuje niedopasowane wartości z dużą dokładnością, dzięki czemu często są łatwe do znalezienia.

Przykład użycia:

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); 
+0

Aby użyć go z Boost :: Ublas :: Vectors, musisz dostosować makro, ale pomysł jest dobry. –

3

Można użyć BOOST_REQUIRE_EQUAL_COLLECTIONS z std::vector<T>, ale trzeba nauczyć Boost.Test jak wydrukować std::vector gdy masz wektor wektorów lub mapy, których wartości są wektorami. Kiedy masz mapę, Boost.Test należy nauczyć, jak drukować std::pair. Ponieważ nie można zmienić definicji std::vector lub std::pair, należy to zrobić w taki sposób, aby zdefiniowany operator wstawiania strumienia był używany przez Boost.Test bez bycia częścią definicji klasy std::vector. Ta technika jest również przydatna, jeśli nie chcesz dodawać operatorów obsługujących strumień do testowanego systemu, aby uczynić Boost.Test szczęśliwym.

Oto przepis dla każdego 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 << ']'; 
} 

} 

formatuje to wektory jak [e1,e2,e3,...,eN] przez wektor z N elementów i działa na dowolną liczbę wektorów, na przykład zagnieżdżone gdzie elementy wektora są również wektorami.

Oto podobny przepis na 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 powie indeks niedopasowanych elementów, jak również zawartość dwóch zbiorów, zakładając, że oba zbiory są tej samej wielkości. Jeśli mają one różne rozmiary, oznacza to niedopasowanie i drukowane są różne rozmiary.

+0

Dobra uwaga, dziękuję za wzmiankę o tym. Musiałem kilkakrotnie dodać podobny kod do moich testów jednostkowych. – mskfisher

+0

Przy doładowaniu 1,33 należy użyć wrap_stringstream :: wrapped_stream zamiast wrap_stringstream, w powyższym kodzie. –

2

Od wersji Boost 1.59 znacznie łatwiej jest porównywać instancje std::vector. Zobacz this documentation dla wersji 1.63 (która jest prawie równa pod tym względem do 1.59).

Na przykład jeśli zadeklarowali std::vector<int> a, b; można napisać

BOOST_TEST(a == b); 

uzyskać bardzo podstawowe porównanie. Wadą tego jest to, że w przypadku niepowodzenia Boost mówi tylko, że a i b nie są takie same. Ale masz więcej informacji, porównując elementem mądry co jest możliwe w elegancki sposób

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

Albo jeśli chcesz leksykograficzny porównania możesz zrobić

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

Doskonale, dzięki! Jestem również podekscytowany wyświetleniem BOOST_TEST_CONTEXT, który prawdopodobnie został dodany w wersji 1.59: http://www.boost.org/doc/libs/1_59_0/libs/test/doc/html/boost_test/test_output/contexts.html – mskfisher