2009-09-22 16 views

risposta

72

Vorrei davvero suggerire di guardare Google C++ Mocking Framework. Anche se non vuoi prendere in giro niente, ti permette di scrivere asserzioni piuttosto complicate con facilità.

Per esempio

//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), _)); 

C'è un sacco di matchers per ogni possibile situazione, e si può combinarli per ottenere quasi tutto.

Ti ho detto che il ElementsAre ha bisogno solo del metodo iterators e size() su una classe per funzionare? Quindi non funziona solo con qualsiasi contenitore da STL ma anche con container personalizzati.

Google Mock afferma di essere quasi altrettanto portatile di Google Test e sinceramente non vedo perché non lo useresti. È semplicemente meraviglioso.

+6

Io uso google mock. E sono d'accordo che è fantastico. Non mi sarei mai aspettato di vedere qualcosa del genere per C++. –

+1

"puramente fantastico" lol Ho intenzione di provarlo anch'io –

+2

'ElementsAreArray' è meglio confrontare gli array, dato che' ElementsAre' ha un limite di 10 elementi. –

9

Avevo la stessa identica domanda, quindi ho scritto un paio di macro che fanno confronti tra due contenitori generici. È estensibile a QUALSIASI contenitore che abbia const_iterator, begin e end. Se fallisce, visualizzerà un messaggio dettagliato di dove l'array è andato storto e lo farà per ogni elemento che fallisce; si assicurerà che abbiano la stessa lunghezza; e la posizione nel codice che segnala come non riuscita è la stessa linea in cui si chiama 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) 

Spero che questo funziona per voi (e che in realtà controllare questa risposta due mesi dopo la tua domanda è stata presentata).

+0

Questo è un ottimo approccio! Forse potresti fornire questo a google in modo che lo aggiungano al framework? –

+1

Hanno detto (http://code.google.com/p/googletest/issues/detail?id=231) che scoraggiano l'aggiunta di macro e questa funzionalità è disponibile in una certa misura nel framework di Google Mock. –

4

Mi sono imbattuto in un problema simile con il confronto di matrici in test di google.

Da quando ho avuto bisogno di confronto con base void* e char* (per i test codice di basso livello), io non cosa sia google finta (che sto utilizzando anche nel progetto) o grande macro di Seth mi potrebbe aiutare nella situazione particolare. Ho scritto la seguente macro:

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

I calchi sono lì per fare la macro utilizzabile quando si confrontano void* per altre cose:

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

Tobias nei commenti suggerito colata void* a char* e utilizzando EXPECT_STREQ, un macro che in qualche modo ho perso prima - che sembra un'alternativa migliore.

+2

Preferirei trasmettere il void * a un char * e usando EXPECT_STREQ. Non funzionerebbe anche quello? –

+0

Uno dei motivi per cui ho postato la mia risposta è perché speravo che qualcuno suggerisse un'alternativa migliore. Sembra che tu abbia fatto, Tobias :) – nietaki

+0

Contento di aver potuto aiutare :) –

3

Di seguito è un'affermazione che ho scritto per confrontare [frammenti di] due array in virgola mobile:

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

uso all'interno dei Testing Framework Google è questo:

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

In caso di errore, qualcosa come il seguente output è prodotto:

..\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 

Per approfondita discussione sul confronto di floati I valori dei punti in generale, vedere this.

12

Se avete solo bisogno di controllare se gli array sono uguali, allora la forza bruta funziona anche:

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

// initialize arr1 and arr2 

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

Tuttavia, questo non vi dico quale elemento diverso.

+3

Bene, conoscere la differenza è una specie di punto. – filmil

11

Se si desidera confrontare un puntatore di matrice in stile c con un array utilizzando Google Mock, è possibile passare a std :: vector. Per esempio: ElementsAreArray di

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

Google Mock accetta anche puntatore e la durata che permettono il confronto di due puntatori matrice c-style. Ad esempio:

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

Ho passato troppo tempo a provare a farlo insieme. Grazie a this StackOverlow post per il promemoria sull'inizializzazione di std :: vector iterator. Si noti che questo metodo copierà gli elementi del buffer array nello std :: vector prima del confronto.

+0

Sei il mio eroe! – slaadvak

2

Ho utilizzato un ciclo classico attraverso tutti gli elementi. È possibile utilizzare SCOPED_TRACE per leggere in quale iterazione sono diversi gli elementi dell'array. Questo ti fornisce informazioni aggiuntive rispetto ad altri approcci ed è facile da leggere.

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

Source

+0

Mi piace un po '. Non richiede la copia dei dati in un contenitore stl, ed è abbastanza semplice. Il wrapping di questo in una macro per un tipo comune di confronto di array (come un vettore o una matrice), viene semplicemente fatto e porta a termine il lavoro. – johnb003

Problemi correlati