Codice C Test unitario



Answers

Personalmente mi piace il framework di Google Test .

La vera difficoltà nel test del codice C è la rottura delle dipendenze su moduli esterni in modo da poter isolare il codice in unità. Questo può essere particolarmente problematico quando si sta tentando di eseguire test intorno al codice legacy. In questo caso mi capita spesso di utilizzare il linker per utilizzare le funzioni di stub nei test.

Questo è ciò a cui le persone si riferiscono quando parlano di " cuciture ". In C l'unica opzione è usare il pre-processore o il linker per deridere le tue dipendenze.

Una tipica suite di test in uno dei miei progetti C potrebbe essere simile a questa:

#include "myimplementationfile.c"
#include <gtest/gtest.h>

// Mock out external dependency on mylogger.o
void Logger_log(...){}

TEST(FactorialTest, Zero) {
    EXPECT_EQ(1, Factorial(0));
}

Si noti che in realtà si include il file C e non il file di intestazione . Ciò offre il vantaggio dell'accesso a tutti i membri dei dati statici. Qui metto in pausa il mio logger (che potrebbe essere in logger.o e dare un'implementazione vuota. Ciò significa che il file di test compila e collega in modo indipendente dal resto della base di codice ed esegue in isolamento.

Per quanto riguarda la compilazione incrociata del codice, affinché funzioni, è necessario disporre di buone strutture sul target. Ho fatto questo con googletest cross compilato su Linux su un'architettura PowerPC. Questo ha senso perché ci sono una shell completa e un sistema operativo per raccogliere i risultati. Per gli ambienti meno ricchi (che classifico come qualcosa senza un sistema operativo completo), dovresti semplicemente creare ed eseguire l'host. Dovresti farlo comunque in modo da poter eseguire i test automaticamente come parte della build.

Trovo che testare il codice C ++ sia in genere molto più semplice a causa del fatto che il codice OO è in generale molto meno abbinato rispetto a quello procedurale (ovviamente dipende molto dallo stile di codifica). Anche in C ++ puoi usare trucchi come l'integrazione delle dipendenze e il metodo di sovrascrivere per ottenere cuciture in codice che è altrimenti incapsulato.

Michael Feathers ha un eccellente libro sul test del codice legacy . In un capitolo tratta le tecniche per trattare il codice non OO che consiglio vivamente.

Modifica : ho scritto un post sul blog sul codice procedurale di test unitario, con l' origine disponibile su GitHub .

Modifica : C'è un nuovo libro che esce dai programmatori pragmatici che si rivolge specificamente al codice C di test unitario che consiglio vivamente .

Question

Ho lavorato su un sistema embedded questa estate scritto in modo diretto C. Era un progetto esistente che la società per cui lavoravo aveva rilevato. Mi sono abbastanza abituato a scrivere unit test in Java usando JUnit, ma ero in perdita per quanto riguarda il modo migliore per scrivere test unitari per il codice esistente (che richiedeva il refactoring) così come il nuovo codice aggiunto al sistema.

Esiste un modo per rendere il test del codice C semplice come un'unità testando il codice Java con, ad esempio, JUnit ? Qualsiasi intuizione che si applichi specificamente allo sviluppo integrato (cross-compiling alla piattaforma arm-linux) sarebbe molto apprezzata.




LibU ( http://koanlogic.com/libu ) ha un modulo di test unitario che consente esplicite dipendenze di casi / suite di test, isolamento del test, esecuzione parallela e un formattatore di report personalizzabile (i formati predefiniti sono xml e txt).

La libreria è dotata di licenza BSD e contiene molti altri moduli utili: reti, debug, strutture dati comunemente utilizzate, configurazione, ecc., Se ne hai bisogno nei tuoi progetti ...




Attualmente sto usando il framework di test dell'unità CuTest:

http://cutest.sourceforge.net/

È ideale per i sistemi embedded poiché è molto leggero e semplice. Non ho avuto problemi a farlo funzionare sulla piattaforma di destinazione e sul desktop. Oltre a scrivere i test unitari, tutto ciò che serve è:

  • un file di intestazione incluso ovunque tu stia chiamando le routine CuTest
  • un singolo file 'C' aggiuntivo da compilare / collegare nell'immagine
  • qualche semplice codice aggiunto al main per impostare e chiamare i test di unità - ho solo questo in una funzione main () speciale che viene compilata se UNITTEST viene definito durante la build.

Il sistema deve supportare un heap e alcune funzionalità di stdio (che non tutti hanno i sistemi incorporati). Ma il codice è abbastanza semplice che potresti probabilmente lavorare in alternativa a quei requisiti se la tua piattaforma non li possiede.

Con un uso giudizioso dei blocchi "C" di extern {}, supporta anche il testing di C ++.







Se sei ancora alla ricerca di framework di test, CUnitWin32 è uno per la piattaforma Win32 / NT.

Questo risolve un problema fondamentale che ho dovuto affrontare con altri framework di test. Vale a dire che le variabili globali / statiche sono in uno stato deterministico perché ogni test viene eseguito come processo separato.




API Sanity Checker - framework di test per librerie C / C ++:

Un generatore automatico di test unitari di base per una libreria C / C ++ condivisa. È in grado di generare dati di input ragionevoli (nella maggior parte, ma purtroppo non tutti) per i parametri e di compilare semplici casi di test ("sanity" o "shallow") per ogni funzione nell'API attraverso l'analisi delle dichiarazioni nell'intestazione File.

La qualità dei test generati consente di verificare l'assenza di errori critici in casi d'uso semplici. Lo strumento è in grado di costruire ed eseguire test generati e rilevare arresti anomali (segfault), aborti, tutti i tipi di segnali emessi, codice di ritorno del programma diverso da zero e sospensione del programma.

Esempi:







Si potrebbe anche voler dare un'occhiata a libtap , un framework di test C che emette il Test Anything Protocol (TAP) e quindi si integra bene con una varietà di strumenti che escono per questa tecnologia. È usato principalmente nel mondo della lingua dinamica, ma è facile da usare e sta diventando molto popolare.

Un esempio:

#include <tap.h>

int main () {
    plan(5);

    ok(3 == 3);
    is("fnord", "eek", "two different strings not that way?");
    ok(3 <= 8732, "%d <= %d", 3, 8732);
    like("fnord", "f(yes|no)r*[a-f]$");
    cmp_ok(3, ">=", 10);

    done_testing();
}



Se hai familiarità con JUnit allora ti consiglio CppUnit. http://cppunit.sourceforge.net/cppunit-wiki

Questo presuppone che tu abbia un compilatore c ++ per fare i test unitari. se no, allora sono d'accordo con Adam Rosenfield che controllare è ciò che vuoi.







C'è un CUnit

E Embedded Unit è un framework di test unitario per Embedded C System. Il suo design è stato copiato da JUnit e CUnit e altri, e quindi adattato in qualche modo per Embedded C System. L'unità incorporata non richiede le librerie C std. Tutti gli oggetti sono assegnati all'area const.

E Tessy automatizza i test unitari del software incorporato.







http://code.google.com/p/cmockery/ è un progetto Google Code lanciato di recente che consiste in una libreria C molto semplice da utilizzare per la scrittura dei test di unità.




Non ho fatto molto per testare un'applicazione C legacy prima di iniziare a cercare un modo per simulare le funzioni. Mi servivano male i mock per isolare il file C che voglio testare dagli altri. Ho dato una prova di cmock e penso che lo adotterò.

Cmock analizza i file di intestazione e genera funzioni di simulazione basate sui prototipi che trova. Mock ti permetterà di testare un file C in perfetto isolamento. Tutto quello che dovrai fare è collegare il tuo file di test con mock invece dei tuoi file di oggetti reali.

Un altro vantaggio di cmock è che convaliderà i parametri passati a funzioni fittizie, e ti permetterà di specificare quale valore di ritorno devono fornire i mock. Questo è molto utile per testare diversi flussi di esecuzione nelle tue funzioni.

I test consistono nelle tipiche funzioni testA (), testB () in cui si creano aspettative, chiamate le funzioni per testare e verificare le asserzioni.

L'ultimo passo è generare un corridore per i tuoi test con l'unità. Cmock è legato al quadro di prova dell'unità. Unity è facile da imparare come qualsiasi altro framework di test unitario.

Vale la pena provare e abbastanza facile da capire:

http://sourceforge.net/apps/trac/cmock/wiki

Aggiornamento 1

Un altro quadro che sto studiando è Cmockery.

http://code.google.com/p/cmockery/

Si tratta di un puro framework C che supporta il testing e la simulazione delle unità. Non ha dipendenza dal ruby ​​(contrariamente a Cmock) e ha pochissima dipendenza dalle librerie esterne.

Richiede un po 'più di lavoro manuale per configurare i mock perché non genera codice. Questo non rappresenta molto lavoro per un progetto esistente poiché i prototipi non cambieranno molto: una volta che hai i tuoi mock, non avrai bisogno di cambiarli per un po '(questo è il mio caso). La tipizzazione aggiuntiva fornisce il controllo completo dei mock. Se c'è qualcosa che non ti piace, cambi semplicemente la tua finta.

Non c'è bisogno di un corridore di prova speciale. Hai solo bisogno di creare una serie di test e passarla a una funzione run_tests. Un po 'più di lavoro manuale anche qui, ma mi piace decisamente l'idea di un quadro autonomo autonomo.

Inoltre contiene alcuni trucchi C che non conoscevo.

Nel complesso Cmockery ha bisogno di un po 'più di comprensione dei mock per iniziare. Gli esempi dovrebbero aiutarti a superare questo. Sembra che possa fare il lavoro con una meccanica più semplice.




Abbiamo scritto CHEAT (ospitato su GitHub ) per facilità di utilizzo e portabilità.

Non ha dipendenze e non richiede installazione o configurazione. Sono necessari solo un file di intestazione e un test case.

#include <cheat.h>

CHEAT_TEST(mathematics_still_work,
    cheat_assert(2 + 2 == 4);
    cheat_assert_not(2 + 2 == 5);
)

I test vengono compilati in un eseguibile che si occupa dell'esecuzione dei test e della segnalazione dei risultati.

$ gcc -I . tests.c
$ ./a.out
..
---
2 successful of 2 run
SUCCESS

Ha anche dei bei colori.






Related