Domanda

Uso il framework Boost Test per testare l'unità del mio codice C ++ e mi chiedevo se è possibile verificare se una funzione affermerà? Sì, sembra un po 'strano ma abbi pazienza! Molte delle mie funzioni controllano i parametri di input al momento dell'inserimento, affermando se non sono validi e sarebbe utile verificarlo. Ad esempio:

void MyFunction(int param)
{
    assert(param > 0); // param cannot be less than 1
    ...
}

Vorrei poter fare qualcosa del genere:

BOOST_CHECK_ASSERT(MyFunction(0), true);
BOOST_CHECK_ASSERT(MyFunction(-1), true);
BOOST_CHECK_ASSERT(MyFunction(1), false);
...

Puoi verificare le eccezioni lanciate usando Boost Test, quindi mi chiedevo se ci fosse anche qualcosa di assertivo di magia ...

È stato utile?

Soluzione

Non credo. Puoi sempre scrivere la tua affermazione che genera un'eccezione e quindi utilizzare BOOST_CHECK_NOTHROW () per tale eccezione.

Altri suggerimenti

Avendo lo stesso problema, ho cercato nella documentazione (e nel codice) e trovato un " soluzione " ;.

Boost UTF utilizza boost::execution_monitor (in <boost/test/execution_monitor.hpp>). Questo è progettato con l'obiettivo di catturare tutto ciò che potrebbe accadere durante l'esecuzione del test. Quando viene trovata un'affermazione esecuzione_monitor lo intercetta e genera boost::execution_exception. Così, utilizzando BOOST_REQUIRE_THROW puoi far valere il fallimento di un'affermazione.

così:

#include <boost/test/unit_test.hpp>
#include <boost/test/execution_monitor.hpp>  // for execution_exception

BOOST_AUTO_TEST_CASE(case_1)
{
  BOOST_REQUIRE_THROW(function_w_failing_assert(),
                      boost::execution_exception);
}

Dovrebbe fare il trucco. (Funziona per me.)

Tuttavia (o dichiarazioni di non responsabilità):

  • Funziona per me. Cioè, su Windows XP, MSVC 7.1, boost 1.41.0. Potrebbe essere inadatto o rotto sulla tua configurazione.

  • Potrebbe non essere l'intenzione dell'autore di Boost Test. (sebbene sembri essere lo scopo di carne_monitor).

  • Tratterà ogni forma di errore fatale allo stesso modo. E potrebbe essere che qualcosa di diverso dalla tua affermazione sta fallendo. In questo caso tu potrebbe mancare un errore di danneggiamento della memoria e / o mancare un'asserzione fallita fallita.

  • Potrebbe interrompersi in future versioni boost.

  • Mi aspetto che fallirebbe se eseguito in Release config, poiché l'assert sarà disabilitato e il codice impostato dall'asserzione per impedire la volontà correre. Con conseguente comportamento molto indefinito.

  • Se, in Release config per msvc, qualche errore assertivo o altri errori fatali si verificherebbe comunque non verrebbe catturato. (vedi documenti di esecuzione_monitor).

  • Se usi assert o no dipende da te. Mi piacciono.

See:

Inoltre, grazie a Gennadiy Rozental (autore di Boost Test), se ti capita leggi questo, ottimo lavoro !!

Esistono due tipi di errori che mi piace verificare: invarianti ed errori di runtime.

Gli invarianti sono cose che dovrebbero essere sempre vere, qualunque cosa accada. Per quelli, uso assert. Cose come te non dovrebbero farmi passare un puntatore zero per il buffer di output che mi stai dando. È un bug nel codice, chiaro e semplice. In una build di debug, si affermerà e mi darà la possibilità di correggerlo. In una build al dettaglio, causerà una violazione di accesso e genererà un minidump (Windows, almeno nel mio codice) o un coredump (Mac / unix). Non c'è catch che posso fare che abbia senso affrontare il dereferenziamento di un puntatore zero. Su Windows catch (...) può sopprimere le violazioni dell'accesso e dare all'utente un falso senso di fiducia che le cose vanno bene quando sono già andate orribilmente, orribilmente in errore.

Questo è uno dei motivi per cui sono arrivato a credere che main sia generalmente un odore di codice in C ++ e l'unico posto ragionevole in cui riesco a pensare di essere presente sia in WinMain (o <=>) giusto prima di generare un dump principale e uscire educatamente dall'app.

Gli errori di runtime sono cose come " Non riesco a scrivere questo file a causa delle autorizzazioni " o " Non riesco a scrivere questo file perché il disco è pieno " ;. Per questo tipo di errori, generare un'eccezione ha senso perché l'utente può fare qualcosa al riguardo, come modificare l'autorizzazione su una directory, eliminare alcuni file o scegliere una posizione alternativa per salvare il file. Questi errori di runtime sono correggibili dall'utente. Una violazione di un invariante non può essere corretta dall'utente, solo da un programmatore. (A volte i due sono uguali, ma in genere non lo sono.)

I test unitari dovrebbero forzare il codice a generare le eccezioni di errore di runtime che il codice potrebbe generare. Potresti anche voler forzare le eccezioni dai tuoi collaboratori per garantire che il tuo sistema in prova sia eccezionalmente sicuro.

Tuttavia, non credo ci sia valore nel cercare di forzare il tuo codice a far valere gli invarianti con unit test.

Penso che questa domanda, e alcune delle risposte, confondano il rilevamento degli errori di runtime con il rilevamento dei bug. Inoltre confondono l'intento e il meccanismo.

L'errore di runtime è qualcosa che può accadere in un programma corretto al 100%. Ha bisogno di essere rilevato, necessita di report e gestione adeguati e dovrebbe essere testato. Si verificano anche errori e, per comodità del programmatore, è meglio individuarli in anticipo utilizzando controlli precondizionati o controlli invarianti o asserzioni casuali. Ma questo è lo strumento del programmatore. Il messaggio di errore non ha alcun senso per l'utente ordinario e non sembra ragionevole testare il comportamento della funzione sui dati che il programma scritto correttamente non gli passerà mai.

Per quanto riguarda l'intento e il meccanismo, va notato che l'eccezione non è nulla di magico. Qualche tempo fa, Peter Dimov ha detto alla mailing list di Boost (approssimativamente) che & Quot; le eccezioni sono solo meccanismi di salto non locali & Quot ;. E questo è molto vero. Se si dispone di un'applicazione in cui è possibile continuare dopo alcuni errori interni, senza il rischio che qualcosa venga danneggiato prima della riparazione, è possibile implementare un'asserzione personalizzata che genera un'eccezione C ++. Ma ciò non cambierebbe l'intento e non renderebbe molto più ragionevole il test per affermazioni.

Al lavoro mi sono imbattuto nello stesso problema. La mia soluzione è usare un flag di compilazione. Quando il mio flag GROKUS_TESTABLE è sul mio GROKUS_ASSERT si trasforma in un'eccezione e con Boost puoi testare percorsi di codice che generano eccezioni. Quando GROKUS_TESTABLE è disattivato, GROKUS_ASSERT viene tradotto in c ++ assert ().

#if GROKUS_TESTABLE
#define GROKUS_ASSERT ... // exception
#define GROKUS_CHECK_THROW    BOOST_CHECK_THROW
#else
#define GROKUS_ASSERT ... // assert
#define GROKUS_CHECK_THROW(statement, exception)  {}  // no-op
#endif

La mia motivazione originale era di aiutare il debug, cioè assert () può essere debug rapidamente e le eccezioni sono spesso più difficili da debug in gdb. Il mio flag di compilazione sembra bilanciare abbastanza bene la debuggabilità e la testabilità.

Spero che questo aiuti

Siamo spiacenti, ma stai attaccando il tuo problema nel modo sbagliato.

&

quot; quot affermare &; è lo spawn del diavolo (a.k.a. " C ") ed è inutile con qualsiasi linguaggio che abbia le giuste eccezioni. È sicuramente meglio reimplementare una funzionalità assertiva con eccezioni. In questo modo si ottiene effettivamente la possibilità di gestire gli errori nel modo giusto (comprese le corrette procedure di pulizia) o di attivarli a piacimento (per test unitari).

Inoltre, se il tuo codice viene mai eseguito in Windows, quando fallisci un'asserzione ottieni un popup inutile che ti offre di eseguire il debug / interrompere / riprovare. Ottimo per test unitari automatizzati.

Quindi fatevi un favore e ricodificate una funzione di asserzione che genera eccezioni. Ce n'è uno qui: Come posso affermare () senza usare abort ()?

Avvolgilo in una macro in modo da ottenere _ _FILE _ _ e _ _ LINE _ _ (utile per il debug) e il gioco è fatto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top