In generale, sono d'accordo con la risposta di Wes - sarà molto più difficile aggiungere test al codice che non è stato scritto con i test in mente. Non c'è nulla di intrinseco in C che rende impossibile testare, ma poiché C non ti obbliga a scrivere in uno stile particolare, è anche molto facile scrivere codice C difficile da testare.
A mio parere, la scrittura di codice con test in mente incoraggerà funzioni più brevi, con pochi argomenti, che aiuta ad alleviare parte del dolore nei vostri esempi.
In primo luogo, è necessario selezionare un framework di test dell'unità. Ci sono molti esempi in this question (anche se purtroppo molte delle risposte sono framework C++ - sconsiglio di usare C++ per testare C).
Io personalmente uso TestDept, perché è semplice da usare, leggero e consente lo stub. Tuttavia, non penso che sia ancora molto usato. Se stai cercando un framework più popolare, molte persone raccomandano lo Check - il che è ottimo se usi automake.
Ecco alcune risposte specifiche per i vostri casi d'uso:
passando intorno una grande 'contesto' struct puntatore
Per questo caso, si può costruire un'istanza della struct con le condizioni pre impostate manualmente, quindi controllare lo stato della struttura dopo che la funzione è stata eseguita. Con funzioni brevi, ogni test sarà abbastanza semplice.
modo semplice al fallimento del test sulle funzioni dipendenti
Credo che questo sia uno dei più grandi ostacoli con unità di test C. che ho avuto successo con TestDept, che permette di tempo di esecuzione stub delle funzioni dipendenti. Questo è ottimo per spezzare il codice strettamente accoppiato. Ecco un esempio dalla loro documentazione:
void test_stringify_cannot_malloc_returns_sane_result() {
replace_function(&malloc, &always_failing_malloc);
char *h = stringify('h');
assert_string_equals("cannot_stringify", h);
}
A seconda dell'ambiente di destinazione, questo potrebbe non funzionare per voi. Vedi their documentation per maggiori dettagli.
funzioni con un sacco di parametri
questo probabilmente non è la risposta che stai cercando, ma vorrei solo spezzare questi fino in funzioni più piccole con meno parametri. Molto più facile da testare.
funzioni statiche o nascoste
non è super pulito, ma ho provato funzioni statiche includendo il file sorgente direttamente, consentendo chiamate di funzioni statiche. Combinato con TestDept per eliminare tutto ciò che non è sotto test, funziona abbastanza bene.
#include "implementation.c"
/* Now I can call foo(), defined static in implementation.c */
un sacco di codice C è il codice legacy con poche prove - e in quei casi, è generalmente più facile per aggiungere i test di integrazione che mettono alla prova le grandi parti del codice prima, invece di unit test grana fine . Ciò consente di avviare il refactoring del codice al di sotto del test di integrazione a uno stato verificabile dall'unità, sebbene possa valere o meno l'investimento, a seconda della situazione.Ovviamente, vorrai essere in grado di aggiungere test unitari a qualsiasi nuovo codice scritto durante questo periodo, quindi avere una solida infrastruttura pronta per l'uso è una buona idea.
Se si con codice legacy, this book (Lavorare efficacemente con codice legacy di Michael Feathers) è un'ottima lettura.
[Possibile duplicato] (http://stackoverflow.com/questions/65820/unit-testing-c-code), se non solo correlato. – ajp15243
@ ajp15243: Sono meno interessato a quale framework o strumento utilizzare quando si esegue il test dell'unità. Piuttosto, mi interessano i modi per scrivere test per il codice C che è altamente dipendente o usa idiomi C comuni, come una struttura 'global_context_t' che viene passata in giro. – MarkP
Bene, modificherei la parte "duplicata" se potessi a questo punto. Pensavo potessi trovare almeno i quadri utili, ma vabbè: /. – ajp15243