2010-10-22 4 views
16

Ich verwende Boost Test, um einige C++ - Code zu testen.Wie vergleicht man Vektoren mit Boost.Test?

Ich habe einen Vektor von Werten, die ich mit den erwarteten Ergebnissen vergleichen müssen, aber ich möchte nicht manuell die Werte in einer Schleife überprüfen:

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

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

Das Hauptproblem ist, dass die Loopcheck doesn Wenn Sie den Index nicht drucken, müssen Sie suchen, um den Unterschied zu finden.

Ich könnte std::equal oder std::mismatch auf den beiden Vektoren verwenden, aber das wird eine Menge Boilerplate ebenso benötigen.

Gibt es einen saubereren Weg, dies zu tun?

Antwort

30

Verwenden Sie BOOST_CHECK_EQUAL_COLLECTIONS. Es ist ein Makro in test_tools.hpp, die zwei Paare von Iteratoren nimmt:

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

Es werden die Indizes und die Werte berichten, stimmen nicht überein. Wenn die Größen nicht übereinstimmen, wird dies ebenfalls gemeldet (und wird nicht einfach über das Ende des Vektors hinauslaufen).


Beachten Sie, dass, wenn Sie BOOST_CHECK_EQUAL oder BOOST_CHECK_EQUAL_COLLECTIONS mit nicht-POD-Typen verwenden möchten, müssen Sie

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

für den Vergleich und die Protokollierung bzw. implementieren.
Die Reihenfolge der Iteratoren, die an BOOST_CHECK_EQUAL_COLLECTIONS übergeben werden, bestimmt, welche der RHS und LHS des Vergleichs != ist - der erste Iteratorbereich wird die LHS in den Vergleichen sein.

+2

tun dies in der Dokumentation ist, dann ist es nur gut versteckt –

+1

Ja, ich bin beschäftigt, meine Schande zu bearbeiten. :) Danke für deine Beispiele in deiner Antwort. – mskfisher

+0

Es ist ein bisschen zu aufdringlich, das zu testende System zu zwingen, 'operator! =' Und 'operator << zu implementieren, nur um Boost.Test, IMO zu erfüllen. Außerdem können Sie diese Memberfunktionen für 'std :: vector' nicht definieren. Siehe meine Antwort unten für eine bessere Lösung. – legalize

10

Wie wäre es mit 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); 
} 

Beispiel

1 verlauf Prüffall ...

test.cpp (11): Fehler in "Test": check {COL1 spalte1 + 7} == {Col2 , col2 + 7} fehlgeschlagen.

Mismatch in der Lage, 2: 3 = 4

Mismatch in einer Position 5: 6 = 7

* 1 in Testreihe "example" erfasste Fehler

9

Ein bisschen off-topic jedoch, wenn manchmal Sammlungen von Fließkommazahlen mit comparison with tolerance vergleichen müssen, dann kann dieses Schnipsel von Nutzen sein:

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

Die Array-Indizes nicht übereinstimmender Elemente werden nicht gedruckt, aber die nicht übereinstimmenden Werte werden mit hoher Genauigkeit gedruckt, sodass sie oft leicht zu finden sind.

Beispiel Nutzung:

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

Für die Verwendung mit Boost :: Ublas :: Vektoren müssen Sie das Makro anpassen, aber die Idee ist gut. –

3

Sie BOOST_REQUIRE_EQUAL_COLLECTIONS mit std::vector<T> verwenden können, aber Sie haben Boost.Test zu lehren, wie ein std::vector zu drucken, wenn Sie einen Vektor von Vektoren oder eine Karte, deren Werte Vektoren haben. Wenn Sie eine Karte haben, muss Boost.Test gelernt werden, wie man std::pair druckt. Da Sie die Definition von std::vector oder std::pair nicht ändern können, müssen Sie dies so tun, dass der von Ihnen definierte Stream-Insertion-Operator von Boost.Test verwendet wird, ohne Teil der Klassendefinition von std::vector zu sein. Außerdem ist diese Technik nützlich, wenn Sie keine Stream-Insertion-Operatoren zu Ihrem getesteten System hinzufügen möchten, um Boost.Test glücklich zu machen. Hier

ist das Rezept für jede 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 << ']'; 
} 

} 

Dieser formatiert die Vektoren als [e1,e2,e3,...,eN] für einen Vektor mit N Elemente und wird für eine beliebige Anzahl von verschachtelten arbeiten Vektoren, z.B. wo die Elemente des Vektors auch Vektoren sind.

Hier ist das ähnliche Rezept für 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 werden Ihnen sagen, den Index der nicht übereinstimmen Elemente sowie die Inhalte der beiden Sammlungen, unter der Annahme, die beiden Sammlungen von gleicher Größe sind. Wenn sie unterschiedlich groß sind, wird das als Mismatch betrachtet und die unterschiedlichen Größen werden gedruckt.

+0

Guter Punkt, vielen Dank für die Erwähnung. Ich musste meinen Komponententests mehrmals einen ähnlichen Code hinzufügen. – mskfisher

+0

Mit Boost 1.33 sollte man im obigen Code wrap_stringstream :: wrapped_stream statt wrap_stringstream verwenden. –

2

Seit Boost 1.59 ist es viel einfacher std::vector Instanzen zu vergleichen. Siehe this documentation für Version 1.63 (was in dieser Hinsicht ungefähr gleich 1,59 ist).

Zum Beispiel, wenn Sie haben std::vector<int> a, b; erklären Sie

BOOST_TEST(a == b); 

bekommen einen sehr einfachen Vergleich zu schreiben. Der Nachteil davon ist, dass Boost im Falle eines Fehlers nur mitteilt, dass a und b nicht identisch sind. Aber Sie erhalten mehr Informationen durch den Vergleich elementweise, die auf elegante Weise möglich ist

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

Oder wenn Sie einen lexicographic Vergleich wollen, können Sie

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

Ausgezeichnet, danke! Ich freue mich auch, BOOST_TEST_CONTEXT zu sehen, das anscheinend in 1.59 hinzugefügt wurde: http://www.boost.org/doc/libs/1_59_0/libs/test/doc/html/boost_test/test_output/contexts.html – mskfisher