Vergleich von Arrays in Google Test?

81

Ich möchte zwei Arrays in Google Test vergleichen. In UnitTest ++ erfolgt dies über CHECK_ARRAY_EQUAL. Wie machst du das in Google Test?

Tobias Furuholm
quelle

Antworten:

115

Ich würde wirklich empfehlen, sich Google C ++ Mocking Framework anzuschauen . Selbst wenn Sie sich über nichts lustig machen möchten, können Sie mit Leichtigkeit ziemlich komplizierte Aussagen schreiben.

Zum Beispiel

//checks that vector v is {5, 10, 15}
ASSERT_THAT(v, ElementsAre(5, 10, 15));

//checks that map m only have elements 1 => 10, 2 => 20
ASSERT_THAT(m, ElementsAre(Pair(1, 10), Pair(2, 20)));

//checks that in vector v all the elements are greater than 10 and less than 20
ASSERT_THAT(v, Each(AllOf(Gt(10), Lt(20))));

//checks that vector v consist of 
//   5, number greater than 10, anything.
ASSERT_THAT(v, ElementsAre(5, Gt(10), _));

Es gibt viele Matcher für jede mögliche Situation, und Sie können sie kombinieren, um fast alles zu erreichen.

Habe ich dir gesagt, dass ElementsArenur eine Methode iteratorsund eine size()Methode für eine Klasse funktionieren? Es funktioniert also nicht nur mit jedem Container von STL, sondern auch mit benutzerdefinierten Containern.

Google Mock behauptet, fast so portabel zu sein wie Google Test, und ehrlich gesagt verstehe ich nicht, warum Sie es nicht verwenden würden. Es ist einfach nur großartig.

vava
quelle
7
Ich benutze Google Mock. Und ich stimme zu, dass es großartig ist. Ich hätte nie erwartet, so etwas für C ++ zu sehen.
Tobias Furuholm
2
ElementsAreArrayist besser, Arrays zu vergleichen, da ElementsArees eine Grenze von 10 Elementen hat.
BЈовић
2
Beachten Sie, dass Sie in Tests möglicherweise EXPECT_THAT anstelle von ASSERT_THAT verwenden möchten.
Arhuaco
Was ist, wenn die Elemente std :: string sind? Ich habe einen Linker-Fehler testing::Matcher<std::string const&>::Matcher(char const*)nicht definiert
Frank Liu
1
Wie BЈовић ElementsAreArray erwähnte, ist hier ein Beispiel für die Verwendung dessen: EXPECT_THAT(v, ElementsAreArray(u));das ich mehr verwendet habe als die aktuellen Beispiele.
Zitrax
18

Wenn Sie nur überprüfen müssen, ob die Arrays gleich sind, funktioniert die Brute Force auch:

int arr1[10];
int arr2[10];

// initialize arr1 and arr2

EXPECT_TRUE( 0 == std::memcmp( arr1, arr2, sizeof( arr1 ) ) );

Dies sagt Ihnen jedoch nicht, welches Element sich unterscheidet.

BЈовић
quelle
15

Wenn Sie einen Array-Zeiger im C-Stil mit Google Mock mit einem Array vergleichen möchten, können Sie std :: vector durchgehen. Zum Beispiel:

uint8_t expect[] = {1, 2, 3, 42};
uint8_t * buffer = expect;
uint32_t buffer_size = sizeof(expect) / sizeof(expect[0]);
ASSERT_THAT(std::vector<uint8_t>(buffer, buffer + buffer_size), 
            ::testing::ElementsAreArray(expect));

ElementsAreArray von Google Mock akzeptiert auch Zeiger und Längen, mit denen zwei Array-Zeiger im C-Stil verglichen werden können. Zum Beispiel:

ASSERT_THAT(std::vector<uint8_t>(buffer, buffer + buffer_size), 
            ::testing::ElementsAreArray(buffer, buffer_size));

Ich habe viel zu lange versucht, dies zusammenzusetzen. Vielen Dank an diesen StackOverflow-Beitrag für die Erinnerung an die Initialisierung des std :: vector-Iterators. Beachten Sie, dass diese Methode die Pufferarray-Elemente vor dem Vergleich in den Vektor std :: kopiert.

Matt Liberty
quelle
1
Wenn der Fehler im getesteten Code zufällig der Fehler ist, auf den ein vom zu testenden Code zurückgegebener buffer_sizeWert falsch gesetzt wird (size_t)-1, was kein ungewöhnlicher Fehler ist, versucht der Vektorkonstruktor, einen sehr großen Vektor zu erstellen ! Das Testprogramm wird möglicherweise mit einem Ressourcenlimit oder einem Speicherfehler oder einem einfachen Absturz beendet, anstatt dass die Testzusicherung fehlschlägt. In C ++ 20 sollte die Verwendung std::spananstelle von Vektor dies verhindern, da der Puffer nicht in einen neuen Container kopiert werden muss.
TrentP
Ähnliches könnte erreicht werden, indem das Casting der actualData in den Zeiger std :: array <type, size> neu interpretiert und der ptr dereferenziert wird. in der Behauptung. So etwas wie: gist.github.com/daantimmer/…
Daan Timmer
13
ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length";

for (int i = 0; i < x.size(); ++i) {
  EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i;
}

Quelle

Николай Русскин
quelle
Irgendwie mag ich das. Es erfordert kein Kopieren der Daten in einen STL-Container und ist einfach. Das Einwickeln in ein Makro für einen gängigen Array-Vergleichstyp (wie einen Vektor oder eine Matrix) erfolgt einfach und erledigt die Aufgabe.
Johnb003
9

Ich hatte genau die gleiche Frage, also habe ich ein paar Makros geschrieben, die Vergleiche zwischen zwei generischen Containern anstellen. Es ist erweiterbar auf jeden Behälter, der hat const_iterator, beginund end. Wenn dies fehlschlägt, wird eine ausführliche Meldung angezeigt, wo das Array fehlerhaft war, und dies für jedes Element, das fehlschlägt. es wird sicherstellen, dass sie die gleiche Länge haben; und der Ort in Ihrem Code, den er als fehlerhaft meldet, ist dieselbe Zeile, in der Sie anrufen EXPECT_ITERABLE_EQ( std::vector< double >, a, b).

//! Using the google test framework, check all elements of two containers
#define EXPECT_ITERABLE_BASE( PREDICATE, REFTYPE, TARTYPE, ref, target) \
    { \
    const REFTYPE& ref_(ref); \
    const TARTYPE& target_(target); \
    REFTYPE::const_iterator refIter = ref_.begin(); \
    TARTYPE::const_iterator tarIter = target_.begin(); \
    unsigned int i = 0; \
    while(refIter != ref_.end()) { \
        if ( tarIter == target_.end() ) { \
            ADD_FAILURE() << #target " has a smaller length than " #ref ; \
            break; \
        } \
        PREDICATE(* refIter, * tarIter) \
            << "Containers " #ref  " (refIter) and " #target " (tarIter)" \
               " differ at index " << i; \
        ++refIter; ++tarIter; ++i; \
    } \
    EXPECT_TRUE( tarIter == target_.end() ) \
        << #ref " has a smaller length than " #target ; \
    }

//! Check that all elements of two same-type containers are equal
#define EXPECT_ITERABLE_EQ( TYPE, ref, target) \
    EXPECT_ITERABLE_BASE( EXPECT_EQ, TYPE, TYPE, ref, target )

//! Check that all elements of two different-type containers are equal
#define EXPECT_ITERABLE_EQ2( REFTYPE, TARTYPE, ref, target) \
    EXPECT_ITERABLE_BASE( EXPECT_EQ, REFTYPE, TARTYPE, ref, target )

//! Check that all elements of two same-type containers of doubles are equal
#define EXPECT_ITERABLE_DOUBLE_EQ( TYPE, ref, target) \
    EXPECT_ITERABLE_BASE( EXPECT_DOUBLE_EQ, TYPE, TYPE, ref, target )

Hoffe, dass dies für Sie funktioniert (und dass Sie diese Antwort zwei Monate nach dem Absenden Ihrer Frage tatsächlich überprüfen).

Seth Johnson
quelle
Das ist ein großartiger Ansatz! Vielleicht könnten Sie dies Google zur Verfügung stellen, damit es dem Framework hinzugefügt wird?
Tobias Furuholm
2
Sie sagten ( code.google.com/p/googletest/issues/detail?id=231 ), dass sie vom Hinzufügen von Makros abraten , und diese Funktionalität ist in gewissem Umfang im Google Mock-Framework verfügbar.
Seth Johnson
5

Ich hatte ein ähnliches Problem beim Vergleichen von Arrays in Google Test .

Da ich einen Vergleich mit Basic void*und char*(für Low-Level-Code-Tests) brauchte , habe ich weder Google Mock (das ich auch im Projekt verwende) noch Seths großartiges Makro, das mir in der jeweiligen Situation helfen könnte. Ich habe folgendes Makro geschrieben:

#define EXPECT_ARRAY_EQ(TARTYPE, reference, actual, element_count) \
    {\
    TARTYPE* reference_ = static_cast<TARTYPE *> (reference); \
    TARTYPE* actual_ = static_cast<TARTYPE *> (actual); \
    for(int cmp_i = 0; cmp_i < element_count; cmp_i++ ){\
      EXPECT_EQ(reference_[cmp_i], actual_[cmp_i]);\
    }\
    }

Die Casts dienen dazu, das Makro im Vergleich void*zu anderen Dingen nutzbar zu machen :

  void* retrieved = ptr->getData();
  EXPECT_EQ(6, ptr->getSize());
  EXPECT_ARRAY_EQ(char, "data53", retrieved, 6)

Tobias schlug in den Kommentaren vor , ein Makro void*zu char*verwenden EXPECT_STREQ, ein Makro, das ich vorher irgendwie vermisst hatte - was nach einer besseren Alternative aussieht.

Nietaki
quelle
2
Ich würde es vorziehen, die Leere * in ein Zeichen * umzuwandeln und EXPECT_STREQ zu verwenden. Würde das nicht auch funktionieren?
Tobias Furuholm
Einer der Gründe, warum ich meine Antwort gepostet habe, war, dass ich gehofft hatte, jemand würde eine bessere Alternative vorschlagen. Es scheint, Sie haben, Tobias :)
Nietaki
EXPECT_STREQfunktioniert nicht für beliebige Arrays, die keine Elemente enthalten. Ich würde immer noch für @nietakis Lösung stimmen.
Mohammad Dashti
4

Unten ist eine Behauptung, die ich geschrieben habe, um [Fragmente von] zwei Gleitkomma-Arrays zu vergleichen:

/* See
http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
for thorough information about comparing floating point values.
For this particular application we know that the value range is -1 to 1 (audio signal),
so we can compare to absolute delta of 1/2^22 which is the smallest representable value in
a 22-bit recording.
*/
const float FLOAT_INEQUALITY_TOLERANCE = float(1.0 / (1 << 22));


template <class T>
::testing::AssertionResult AreFloatingPointArraysEqual(
                                const T* const expected,
                                const T* const actual,
                                unsigned long length)
{
    ::testing::AssertionResult result = ::testing::AssertionFailure();
    int errorsFound = 0;
    const char* separator = " ";
    for (unsigned long index = 0; index < length; index++)
    {
        if (fabs(expected[index] - actual[index]) > FLOAT_INEQUALITY_TOLERANCE)
        {
            if (errorsFound == 0)
            {
                result << "Differences found:";
            }
            if (errorsFound < 3)
            {
                result << separator
                        << expected[index] << " != " << actual[index]
                        << " @ " << index;
                separator = ", ";
            }
            errorsFound++;
        }
    }
    if (errorsFound > 0)
    {
        result << separator << errorsFound << " differences in total";
        return result;
    }
    return ::testing::AssertionSuccess();
}

Die Verwendung innerhalb des Google Testing Framework ist folgende:

EXPECT_TRUE(AreFloatingPointArraysEqual(expectedArray, actualArray, lengthToCompare));

Im Fehlerfall wird etwa die folgende Ausgabe erzeugt:

..\MyLibraryTestMain.cpp:145: Failure
Value of: AreFloatingPointArraysEqual(expectedArray, actualArray, lengthToCompare)
  Actual: false (Differences found: 0.86119759082794189 != 0.86119747161865234 @ 14, -0.5552707314491272 != -0.55527061223983765 @ 24, 0.047732405364513397 != 0.04773232713341713 @ 36, 339 differences in total)
Expected: true

Weitere Informationen zum Vergleich von Gleitkommawerten im Allgemeinen finden Sie hier .

Astraujums
quelle
3

Ich habe eine klassische Schleife durch alle Elemente verwendet. Mit SCOPED_TRACE können Sie auslesen, in welcher Iteration sich die Array-Elemente unterscheiden. Dies bietet Ihnen im Vergleich zu einigen anderen Ansätzen zusätzliche Informationen und ist leicht zu lesen.

for (int idx=0; idx<ui16DataSize; idx++)
{
    SCOPED_TRACE(idx); //write to the console in which iteration the error occurred
    ASSERT_EQ(array1[idx],array2[idx]);
}
Wintermute
quelle