best practice durante i test unitari per lo sviluppo integrato


45

Sto cercando alcune strategie di buone pratiche per il codice di unit test scritto per il sistema incorporato. Per sistema incorporato, intendo codice come driver di dispositivo, gestori ISR ​​ecc., Cose che sono abbastanza vicine al metallo.

La maggior parte dei test unitari non è possibile senza testarlo sull'hardware con l'aiuto di un ICE. A volte, l'unità incorporata deve anche essere collegata ad altri stimoli come interruttori meccanici, motori passo-passo e lampadine. Questo di solito avviene in modo manuale, l'automazione sarebbe ottima ma difficile e costosa da raggiungere.

Aggiornare

Mi sono imbattuto in un framework di test C che sembra avere abbastanza successo nel test di progetti embedded. Usa le idee di deridere l'hardware. Dai un'occhiata a Unity , CMock e possibilmente Ceedling .

Aggiornamento 06Jul2016

È venuto attraverso cmocka - sembra essere più attivamente lavorato su.


1
In circostanze simili, abbiamo scelto Cmocka
Mawg il

Ho scritto un tutorial molto approfondito sull'argomento: unit-testing di applicazioni C incorporate con Ceedling
Dmitry Frank,

Risposte:


28

Vorrei allontanarmi dalle dipendenze hardware il più presto possibile e costruire il sistema su emulazioni software / cablaggi di test, consentendo tutti i tipi di framework di test. Spesso il mio PC di sviluppo è stato utilizzato per testare fino al 95% o più dell'intero sistema. Il costo dell'overhead aggiuntivo (un altro strato di astrazione) è stato facilmente recuperato dal codice più pulito generato a seguito di tale astrazione.

Il test delle parti veramente baremetal di un sistema embedded è di solito un'applicazione separata (Unit test?) Che martella il firmware ben oltre ciò che le applicazioni possono persino sperare di ottenere. L'automazione può essere eseguita a un costo, ma non è tipica.

A meno che non si disponga di un budget sufficiente per creare un cablaggio hardware di unit test incluso ICE completo. Questo va assolutamente bene in quanto generalmente i test funzionali sono piccoli.


Questo combinato con la risposta di jonathan cline ieee è una strategia di successo. Utilizzare l'astrazione per rendere testabile la maggior parte del codice e, utilizzando un semplice framework di test, testare i bit non estraibili sull'hardware reale. Ho visto personalmente questo lavoro con più piattaforme.
Tim Williscroft,

3
Ogni singolo prodotto che realizziamo ha Hardware Abstraction Layer con implementazione di driver per piattaforma target e PC. Questo ci consente di eseguire facilmente test unitari. Altri vantaggi: possiamo anche eseguire test di sistema rapidi e sviluppare la maggior parte del software senza hardware (poiché sarà disponibile in seguito).
MaR

15

Uno strumento necessario per lo sviluppo è un iniettore di segnale. Il sistema incorporato avrà qualche modo di interfacciarsi con un sistema host (in genere tramite una porta seriale riservata per il debug). Utilizzalo per inviare dati di test (la migliore opzione è formattata ascii in modo da poter essere facilmente simulata anche dall'uomo).

Non sono completamente d'accordo con questa parte della tua domanda: "l'automazione sarebbe grandiosa ma difficile e costosa da raggiungere".

Utilizzando TeraTerm come iniettore di un segnale della porta seriale e scrivendo alcune macro TeraTerm (richiede circa 20 minuti), esiste un'enorme suite di test automatizzati che possono essere eseguiti su qualsiasi parte di un sistema incorporato, sia a livello di driver, O / S, strato 4-5, ecc. TeraTerm: http://en.sourceforge.jp/projects/ttssh2/

Se la porta seriale non è disponibile sul sistema incorporato, utilizzare uno strumento hardware per convertire i dati della porta USB / seriale in segnali digitali (anche economici e facili da ottenere). Mentre leggi questo, sto usando una scheda microcontrollore da $ 30 (UBW: http://www.schmalzhaus.com/UBW32/ ) per testare un sistema incorporato per la produzione, iniettando stimolo tramite macro TeraTerm che viene inviato tramite USB / seriale a il microcontrollore, che esegue un firmware modificato che esercita gli ingressi digitali e monitora le uscite digitali del sistema incorporato di destinazione. Insieme a questo, abbiamo sviluppato uno script Python (utilizza pyserial e pexpect) per automatizzare l'iniezione e la convalida dei dati. Niente di tutto ciò è difficile e nessuno è costoso. Nella mia esperienza, i manager spendono i soldi (come ad esempio $ 30.000 di apparecchiature di test) quando il team di test è inesperto e non riesce a concepire queste soluzioni facili - sfortunatamente, le apparecchiature per uso generale di grandi dimensioni spesso non includono i casi di test che rileva il momento peggiore / ecc. del sistema target. Quindi il metodo economico è preferibile per la copertura del test. Credici o no.


1
Bene, ho fatto la dichiarazione costosa mentre lavoro nel settore automobilistico e tutto deve essere deterministico, ripetibile e di solito ci vogliono un paio di ingegneri per svilupparsi. Inoltre, quando vengono utilizzati più articoli nella catena di test, anche la manutenzione diventa un problema. Grazie per averci informato dell'UBW, sembra una buona opzione.
tehnyit,

2
Solo non farmi iniziare su LabView .. è roba orribile in genere.
Jonathan Cline IEEE

1
I nostri ingegneri di test adorano LabView, non lo capisco da solo.
tehnyit,

Questo è abbastanza vicino a quello che faccio per vari test, solo io uso Python e le loro librerie seriali. Potrei quindi collegare i miei test di basso livello ai tester di unità di Python insieme a qualcosa come Flask / Qt per dare anche un frontend facile da usare.
radix07,

5

Questo è un problema molto difficile

In realtà ho progettato un'unità di test di unità per un sistema incorporato, che consentirebbe di simulare eventi / interruzioni hardware e di controllare i tempi di esecuzione (per garantire che copriamo tutti i possibili intrecci dovuti alla concorrenza), e ci sono voluti un team di programmatori da più di 2 anni per implementarlo e metterlo al lavoro. Tale progetto è uno sviluppo proprietario, ma un progetto simile (più semplice nel design) è disponibile qui .

Quindi sì, l'automazione sarebbe fantastica. Sì, è molto difficile e costoso da raggiungere. Sì, a volte devi farlo. Raramente, nella mia esperienza, nella maggior parte dei casi è più veloce ed economico utilizzare i motori passo-passo e le lampadine e far funzionare tutto manualmente.


Ho scoperto che l'unità è manualmente soggetta a errori, di solito nel generare lo stimolo o nella misurazione dei risultati. Soprattutto se il test unitario è complicato. Se devi ripetere nuovamente il test dell'unità, diventa ancora più incline agli errori.
tehnyit,

@tehnyit - sì, questo è stato il motivo per cui abbiamo deciso di sviluppare il sistema di automazione. A volte le cose non possono essere eseguite manualmente, tuttavia il test unitario deve essere completo e coprire i problemi di temporizzazione. Quindi non hai molta scelta, ma l'automazione a questo livello è una cosa molto costosa da fare.
littleadv,

4

Modifica: la mia risposta è vicina a quella di Mattnz, penso ...


Voglio mettere in relazione questo problema con altri, tutti i test che dipendono da qualcosa di esterno al tuo codice (come l'orologio di sistema, un filesystem persistente o un database, contattando un servizio web esterno ...). Suggerisco la stessa politica per tutti loro, isolare i due livelli in due livelli di codice.

Test di una singola operazione esterna

Potresti voler testare fisicamente ogni operazione. Verifica che l'orologio di sistema dia l'ora corretta, controlla che un file ricordi effettivamente ciò che è stato scritto, controlla che un dispositivo riceva una singola operazione ...

Questi test:

  • dovrebbe essere il più semplice possibile: nessun algoritmo, nessuna condizione o loop
  • potrebbe dipendere dall'ordine e dalla macchina: quindi è necessario seguire un ordine rigoroso e ripetere su ciascun hardware
  • sono per lo più stabili nel corso del progetto, quindi non è necessario eseguirli così spesso
  • quindi eseguirli manualmente è un'opzione; l'automazione è ancora migliore, se non eccessivamente complessa
  • Nota che ciò che viene testato non è il tuo codice , è uno strumento di cui il tuo codice ha bisogno ... Quindi testare questo potrebbe essere facoltativo per te, potrebbe essere stato fatto da un team diverso ...

Test della logica (codice, algoritmo) che collega le operazioni esterne

Avendo uno strato di codice per eseguire le effettive operazioni esterne, nascondendole in un'interfaccia che puoi facilmente deridere, la tua logica non dipende più dai dispositivi fisici reali ...

Puoi testare semplicemente, come qualsiasi progetto normale, non sei più in un codice difficile da testare incorporato .


3

I simulatori di CPU incorporati possono generalmente essere programmati per simulare anche l'hardware. Tutte le tecnologie di virtualizzazione diverse da Xen lo fanno. Ma devi scrivere un codice che finge di avere dei registri su un indirizzo fisico o, su x86, un indirizzo sul bus I / O, quindi devi rispondere a letture e scritture a questi indirizzi come se il tuo software fosse un fisico chip i cui registri di controllo e di stato erano accessibili.

Se vuoi farlo, suggerirei di modificare QEMU. Ma non sarebbe facile. Questo genere di cose viene generalmente eseguito solo quando si progetta un chip personalizzato con un microcontrollore e alcuni altri core per l'I / O.

Il sistema di sviluppo venduto da ARM Holdings prevede questo ed è probabilmente più facile da lavorare rispetto all'hacking su QEMU, ma è molto costoso.

Esistono diversi emulatori ARM Open Source che eseguono una singola subroutine, che può chiamare altre subroutine, che è possibile utilizzare per il debug ottimizzando le prestazioni delle subroutine che non dipendono dall'accesso hardware. Ho usato uno di questi con grande successo per ottimizzare un codificatore AES per ARM7TDMI.

È possibile scrivere un semplice cablaggio di unit test in C o C ++, collegare la classe o la subroutine sotto test ad esso, quindi eseguirlo nel simulatore.

Ho riflettuto su un problema simile per anni, su come testare il codice del kernel Linux o Mac OS X. Dovrebbe essere possibile, ma non ci ho mai provato. Uno probabilmente è quello di costruire un kernel completo piuttosto che testare il codice in modo isolato, con il framework di unit test collegato direttamente nel kernel. Dovresti quindi eseguire il test dell'unità da una sorta di interfaccia esterna.

Forse sarebbe più produttivo utilizzare uno strumento di copertura del codice, quindi testare il firmware come pacchetto completo attraverso la sua interfaccia esterna. Lo strumento di copertura trova percorsi di codice non ancora testati, quindi è possibile aggiungere ulteriori test esterni nel tentativo di ottenere una copertura maggiore.


3

Come con TDD non incorporato, gli oggetti finti sono sicuramente tuoi amici.

Mantieni l'interfaccia al tuo hardware sottostante pulita e semplice in modo che tutto ciò che si trova al di sopra del livello più basso possa essere deriso e avrai un tempo molto più semplice - se si progetta l'applicazione incorporata tenendo presente la testabilità, i test andranno sempre molto più agevolmente .

Inoltre, solo perché potresti non essere in grado di testare online fino a tardi nel progetto non significa che non dovresti preparare anche una serie di test online.

Questi dovrebbero (inizialmente) solo testare i bit che non potevano essere testati offline. Certo, non è TDD (dal momento che stai creando i test in anticipo), ma lo sviluppo TDD offline dovrebbe darti una buona idea di come deve apparire l'interfaccia hardware e quindi di quali test online devi eseguire.

Inoltre, se lo sviluppo online costa molto di più rispetto allo sviluppo offline (come fa dove lavoro), potrebbe farti risparmiare un sacco di tempo online avendo una serie ben compresa di test da eseguire.


+1 per portare oggetti finti sul piatto, @mark. L'unico problema è che garantire l'accuratezza degli oggetti finti, il che significa che comprendere l'oggetto da deridere dovrebbe essere abbastanza profondo. Ciò è positivo poiché costringe lo sviluppatore a comprendere il comportamento degli oggetti esterni a cui si interfaccia.
tehnyit,

1

Nello sviluppo integrato, spesso si eseguono scansioni al contorno per verificare il funzionamento dell'intera applicazione (incluso l'hardware). Vedi anche JTAG per il debug nel sistema.

Il test di routine software pure senza collegamento all'hardware può essere eseguito da un framework di test C Unit standard come Check . Ma attenzione alle limitazioni di memoria (in particolare lo spazio di archiviazione, ecc. Su piccoli dispositivi). Conosci i tuoi contratti! Puoi anche provare a sottrarre le routine software dall'hardware per ottenere una copertura di test più ampia, ma di solito è costoso in termini di prestazioni su dispositivi integrati come PIC piccoli o AVR. Tuttavia, puoi deridere le porte hardware per ottenere una copertura maggiore (e ovviamente puoi anche testare quella simulazione).

Puoi anche provare a usare gli emulatori per i simulatori di chip o circuiti, ma questo tipo di strumenti sono costosi (specialmente in combinazione) e complicati.


Concordo con la scansione dei limiti e JTAG, ma, a causa della progettazione dell'hardware, non è sempre possibile o disponibile.
tehnyit,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.