- Questa domanda non riguarda i framework di unit test.
- Questa domanda non riguarda la scrittura di test unitari.
- Questa domanda riguarda dove inserire il codice UT scritto e come / quando / dove compilarlo ed eseguirlo.
Nel lavorare efficacemente con il codice legacy , Michael Feathers afferma che
buoni test unitari ... corri veloce
e quello
Un test unitario che richiede 1/10 di secondo per essere eseguito è un test unitario lento.
Penso che queste definizioni abbiano un senso. Penso anche che implicano che devi tenere una serie di Test unitari e una serie di Quei test di codice che richiedono più tempo separatamente, ma immagino che sia il prezzo che paghi per chiamare qualcosa un Test unitario se funziona (molto) velocemente .
Ovviamente il problema in C ++ è quella di "correre" il tuo Test Unit ( s ), è necessario:
- Modifica il tuo codice (produzione o Unit Test, a seconda del "ciclo" in cui ti trovi)
- Compilare
- collegamento
- Inizio Unità eseguibile di prova ( s )
Modifica (dopo uno strano voto da vicino) : prima di entrare nei dettagli, proverò a riassumere il punto qui:
Come può essere organizzato in modo efficace il codice C ++ Unit Test, in modo che sia sia efficace modificare il codice (test) sia eseguirlo?
Il primo problema è quindi decidere dove inserire il codice Unit Test in modo che:
- è "naturale" modificarlo e visualizzarlo in combinazione con il codice di produzione associato.
- è facile / veloce avviare il ciclo di compilazione per l'unità attualmente in fase di modifica
Il secondo problema correlato è quindi cosa compilare in modo che il feedback sia istantaneo.
Opzioni estreme:
- Ogni Unit-Test-Test-Unit vive in un file cpp separato e questo file cpp viene compilato + collegato separatamente (insieme al file di unità del codice sorgente testato) a un singolo eseguibile che quindi esegue questo test unitario.
- (+) Ciò minimizza il tempo di avvio (compilazione + collegamento!) Per la singola unità di test.
- (+) Il test viene eseguito molto velocemente, poiché verifica solo un'unità.
- (-) L'esecuzione dell'intera suite dovrà avviare un bazillion di processi. Può essere un problema da gestire.
- (-) Il sovraccarico dell'avvio del processo sarà visibile
- L'altro lato sarebbe avere - ancora - un file cpp per test, ma tutti i file cpp di test (insieme al codice che testano!) Sono collegati in un eseguibile (per modulo / per progetto / scegli la tua scelta).
- (+) Il tempo di compilazione sarebbe ancora OK, poiché verrà compilato solo il codice modificato.
- (+) Eseguire l'intera suite è facile, poiché c'è solo un exe da eseguire.
- (-) La suite impiegherà anni per il collegamento, poiché ogni ricompilazione di qualsiasi oggetto attiverà un nuovo collegamento.
- (-) (?) La tuta impiegherà più tempo a correre, anche se se tutti i test delle unità sono veloci, il tempo dovrebbe essere OK.
Quindi, come vengono gestiti i test unitari C ++ nel mondo reale ? Se eseguo solo quella roba ogni notte / ogni ora, la seconda parte non ha molta importanza, ma la prima parte, vale a dire come "accoppiare" il codice UT al codice di produzione, in modo che sia "naturale" per gli sviluppatori mantenere entrambi in la messa a fuoco conta sempre, penso. (E se gli sviluppatori hanno a fuoco il codice UT, vorranno eseguirlo, il che ci riporta alla seconda parte.)
Storie ed esperienze del mondo reale apprezzate!
Appunti:
- Questa domanda lascia intenzionalmente la piattaforma non specificata e crea / progetta il sistema.
- Domande contrassegnate UT & C ++ è un ottimo punto di partenza, ma purtroppo troppe domande, e in particolare le risposte, sono troppo focalizzate sui dettagli o su quadri specifici.
- Qualche tempo fa, ho risposto a una domanda simile sulla struttura per i test delle unità di boost. Trovo che questa struttura sia carente per "veri", veloci test unitari. E trovo l'altra domanda troppo ristretta, quindi questa nuova domanda.
:-(
Dove pensi di cercare risposte a tali domande se non in questo forum?
Pipeline<A,B>.connect(Pipeline<B,C>)
dovrebbe essere compilato mentre Pipeline<A,B>.connect(Pipeline<C,D>)
non dovrebbe essere compilato: il tipo di output del primo stadio è incompatibile con il tipo di input del secondo stadio.