2011-11-02 24 views
6

sono coinvolto con un progetto che deve, tra le altre cose, che controllano i vari strumenti di laboratorio (robot, lettori, ecc ...)codice Unit-test con dipendenze esterne imprevedibili

La maggior parte di questi strumenti sono controllate sia attraverso Driver basati su DCOM, porta seriale o avvio di programmi proprietari con vari argomenti. Alcuni di questi programmi o driver includono la modalità di simulazione, altri no. Ovviamente, il mio computer di sviluppo non può essere collegato a tutti gli strumenti, e mentre posso avviare macchine virtuali per gli strumenti i cui driver includono una modalità di simulazione, alcune cose non possono essere testate senza lo strumento vero e proprio.

Ora, il mio codice non riguarda principalmente le operazioni effettive sugli strumenti, ma le operazioni di avvio, assicurandosi che tutto funzioni correttamente e la sincronizzazione tra di esse. È scritto in Java, usando varie librerie per interfacciarsi con gli strumenti e i loro driver.

Desidero scrivere test di unità per i vari moduli di controllo dello strumento. Tuttavia, poiché gli strumenti possono fallire in molti modi (alcuni dei quali sono documentati, alcuni dei quali non lo sono), perché il codice dipende da questi output parzialmente casuali, sono un po 'perso riguardo a come scrivere test unitari per queste parti di il mio codice Ho considerato le seguenti soluzioni:

  • unico test con strumenti reali, connessi, forse il metodo più accurato, ma non è affatto pratico (piastra di inserto lettore, eseguire test di unità, rimuovere la piastra, eseguire test di unità, ecc ...), per non parlare di potenzialmente pericoloso,
  • utilizzare un oggetto fittizio per simulare la parte che effettivamente comunica con la cosa; mentre questo è sicuramente più facile da implementare (e funzionare), potrebbe non essere in grado di riprodurre l'intera gamma di potenziali guasti (come già detto, molto è non documentata, che a volte può causare brutte sorprese)

Mentre Attualmente sto pensando di andare con quest'ultimo, mi manchi qualcosa? C'è un modo migliore per farlo?

risposta

6

I due punti elenco sono entrambe opzioni valide, ma ognuna rappresenta due diversi tipi di test.

Ad un livello molto alto, l'utilizzo di oggetti Mock (secondo il tuo secondo punto elenco) è ottimo per Test unità - che sta semplicemente testando il tuo codice (che è il sistema in prova o SUT), e nient'altro estraneo a esso. Qualsiasi altra dipendenza viene derisa. È quindi possibile scrivere casi di test per lanciare il maggior numero di condizioni di errore che si possano pensare (oltre a testare il "percorso felice", ovviamente). Il fatto che il tuo dominio delle condizioni di errore non sia documentato è sfortunato, e qualcosa che dovresti lavorare per ridurlo nel miglior modo possibile. Ogni volta che si verifica una nuova condizione di errore con il dispositivo esterno effettivo, è necessario capire come riprodurlo tramite codice e quindi scrivere un altro nuovo test di unità per ricreare tale condizione attraverso il proprio framework simulato.

Inoltre, il test con gli strumenti effettivi collegati (per il primo punto elenco) è ottimo per i test di integrazione, il che è un ulteriore test del codice insieme alle dipendenze esterne effettive.

In generale, il Test unità dovrebbe essere veloce (idealmente, meno di 10 minuti per compilare il codice ed eseguire l'intera suite di test dell'unità.) Ciò significa che otterrete un feedback rapidamente dai test delle unità, in caso di nuovo codice Ho scritto che ogni test fallisce. Il test di integrazione, per sua natura, può richiedere più tempo (se, ad esempio, uno dei tuoi dispositivi esterni impiega 1 minuto per calcolare un risultato o eseguire un'attività, e hai 15 diversi set di input che stai testando, sono 15 minuti giusti lì per una piccola serie di test.) Il tuo server CI (dovresti avere uno di quelli che compila automaticamente ed esegue tutti i test) dovrebbe essere automaticamente attivato al commit sul tuo repository di controllo del codice sorgente. Dovrebbe compilare ed eseguire i test unitari come un unico passaggio. Dopo che questa parte è stata completata, dovrebbe fornire un feedback (buono o cattivo), e quindi se l'unità verifica tutti i passaggi, dovrebbe automaticamente dare il via ai test di integrazione. Ciò presuppone che sia presente un dispositivo reale collegato al server CI o una sostituzione idonea (qualunque cosa significhi nel proprio ambiente particolare.)

Spero che questo aiuti.

+0

Test delle unità: ho già effettuato la compilazione automatica e il test delle unità per la maggior parte del progetto (in gran parte si tratta di memorizzare/convertire/trasmettere i dati dagli strumenti in modo sicuro). Tuttavia, per testare correttamente il codice di controllo degli strumenti, probabilmente ci vorrà molto più tempo per l'esecuzione, poiché alcune delle condizioni di errore coinvolgono timeout (che, concesso, possono essere portati a un valore ragionevole durante il test). Ma per la parte di integrazione, è più difficile e non può essere automatizzato in alcuni casi, poiché comporta la manipolazione fisica degli strumenti (ad esempio l'aggiunta di una piastra) –

4

Se si utilizzano i mock, è possibile sostituire i vari mock in modo diverso. Cioè, i tuoi test saranno coerenti. Ciò è prezioso poiché eseguire test su un sistema che esegue in modo casuale non ti darà un senso di sicurezza. Ogni esecuzione può/esegue un diverso percorso di codice.

Dal momento che non si conoscono tutti i scenari di errore di anticipo, penso che ci sono due (non esclusivi) scenari:

  1. catturare i dettagli di questi errori come li vedono e codificare ulteriori test in i tuoi scherzi per replicare questi. Di conseguenza, la registrazione deve essere valida, per acquisire i dettagli dell'errore. Col passare del tempo, il set di test si espanderà per comprendere e testare la regressione in questi scenari.
  2. Le interfacce con questo sistema possono essere in grado di acquisire tutti gli errori, ma presentarli in un sottoinsieme finito di errori. per esempio. categorizza tutti gli errori in (diciamo) errori di connessione, timeout, ecc. In questo modo si restringono gli scenari a un piccolo insieme di errori. Non so se questo è pratico per la tua applicazione, sfortunatamente.
3

Non è possibile testare l'unità qualcosa che non si è previsto, per definizione.

Il secondo approccio è appropriato per i test unitari. Avere gli strumenti reali collegati lo rende al meglio un test di integrazione.

Suddividere le dipendenze in modo da poter creare uno strumento falso, e quindi farlo simulare la realtà in tutti i modi possibili. Quando la tua comprensione della realtà migliora, aggiorna il tuo falso e aggiungi i test per far fronte a questa situazione. (In alcuni casi il mocking può essere appropriato, fingendo in altri.)