Test delle unità quando è più difficile trovare casi concreti che scrivere la logica

5

Ho poca esperienza con i test unitari, ma al progetto su cui stiamo lavorando in questo momento abbiamo deciso di fare test unitari. Il progetto è un'applicazione WPF / Entity Framework e la parte su cui mi sto confondendo è una funzione di filtro.

Il nostro universo di entità è così: ci sono prodotti, valutazioni e collezioni.

Valutazione 1 - n Prodotto

Raccolta n - Valutazione

Collezione n - m prodotto

Ora la funzione filtro in questione è chiamata "in collezione" e la logica è la seguente: Includi il prodotto se ha una raccolta in cui Collection.Active == true, o se il prodotto ha una valutazione che a sua volta ha una raccolta.

Quindi, quando l'unità sta testando questo, sto cercando di scoprire i diversi possibili casi d'angolo, e faccio asserzioni circa il fatto che siano inclusi nell'elenco filtrato o meno. Prodotti che hanno una collezione attiva, Prodotti che non hanno una collezione attiva ma che ha una valutazione che ha una collezione e così via.

Il problema è che lavorare su questi casi angusti è molto più complicato rispetto alla scrittura di una semplice query linq-to-entity, e sembra che la probabilità di commettere un errore nel test sia molto più alta di un errore nell'implementazione del filtro.

Come gestiresti queste situazioni? Non sembra insolito, specialmente dove ci sono strumenti che ti permettono di scrivere la logica in un modo semplice. È possibile beneficiare dei test unitari qui? Come?

    
posta Mårten 23.10.2014 - 09:23
fonte

4 risposte

4

L'opinione comune è che quando un test fallisce, il codice testato deve essere in errore. Ma funziona solo se puoi verificare a colpo d'occhio che il test è corretto.

La realtà è che quando un test fallisce, hai trovato una discrepanza tra il caso del test e il codice sotto test. Questa discrepanza è causata da un semplice errore (nel caso di test o dal codice in prova) o da un fraintendimento dei requisiti.
Quando un test fallisce, devi scoprire qual è la causa della discrepanza e quindi correggere sia il test-case che il codice sotto test (o, in rari casi, entrambi).

Anche se scrivere i test per questa funzione è difficile, ti incoraggerei a farlo comunque, poiché la scrittura dei test può rivelare ambiguità nei requisiti e (ripetutamente) l'esecuzione dei test dà fiducia che le modifiche non correlate non hanno infranto il caratteristica.

    
risposta data 23.10.2014 - 09:53
fonte
4

Se avessi intenzione di sviluppare un metodo di test unitario per lo sviluppo di test, allora ti suggerirei di usare il metodo Purist di test delle unità, ovvero, fare un test unitario che fallirebbe poi refactoring il codice per farlo passare .

Anche se si è tentati di saltare test di pezzi di codice molto semplici, ti preghiamo di non farlo perché:

  • Writing Unit Tests mette la fonte della veridicità nei casi di test e non nel codice sorgente (ovvero se il test fallisce magicamente anche se la logica è semplice, significa che qualcuno ha incasinato il codice base che causa la logica del test a Immagina se la fonte della verità sia nel tuo codice, se il test dovesse fallire, allora l'assunzione di alcune persone è che il test è stato scritto in modo errato invece di pensare che l'implementazione del loro codice sia sbagliata)
  • Assicurazione. I test unitari ti consentono di individuare i bug nella fase di sviluppo, quindi usali il più spesso possibile. Diamine, incoraggerei persino a mirare a una copertura del 100% dei test del tuo codice base, in quanto ciò ti farebbe risparmiare la fatica di dover testare l'intera base di codice per essere sicuro che il tuo refactoring non abbia infranto una dichiarazione condizionale innocente un metodo che usi solo una volta in una luna blu.

Nota: Inoltre, se hai un po 'di problemi nello scrivere semplici test unitari, ti suggerisco di dare un'occhiata al cetriolo e al suo genere . BDD ti consente di scrivere casi di test in modo più naturale, quindi in alcuni casi potrebbe essere più semplice per te.

Nota 2: Come @gbjbaanb, detto nei commenti qui sotto, anche con la copertura del test LOC al 100%, non è ancora possibile sostituire il test manuale e il QA. Sebbene la scrittura di test automatici come questi aiuti a ridurre il carico sul tester.

    
risposta data 23.10.2014 - 10:24
fonte
2

Scrivi comunque il test. Se è parte del contratto software che deve essere testato, è irrilevante la semplicità della funzionalità. È il processo di test rigoroso in una notazione secondaria che conta. Combinato con il codice di destinazione e gli altri client del codice, il test costituisce un quorum di tre che ne verifica la correttezza. Puoi scrivere un bug una volta, ma è meno probabile che lo farai due volte a meno che tu non abbia frainteso la logica o che la specifica fosse sbagliata.

I test delle tue unità:

  1. Convalida i tuoi contratti man mano che sviluppi
  2. Convalida il tuo modo di pensare. (Ho sentito il debugging dell'anatra di gomma?)
  3. Diventa documentazione
  4. Proteggi le API dalla violazione accidentale. Se il codice si rompe, il test urla a squarciagola. Un nuovo dev nel prossimo cubo potrebbe pensare che il tuo strano algoritmo sia un bug o un codice inutile, finché il suo "fix" non interrompe il test.
  5. Guarda dopo di te quando sei stanco e ti proteggono dal controllare qualcosa di stupido. Lo facciamo tutti di tanto in tanto. Meglio un test ti urla rispetto ai tuoi compagni di squadra. :)

I test sono l'unico modo per dimostrare sistematicamente che il tuo software fa quello che dovrebbe fare. Fidati di me c'è qualcosa di molto confortante e soddisfacente nel vedere i tuoi test unitari superare il 100% dopo un lungo ciclo di revisione.

Più tardi, se esci, un altro sviluppatore può trarre vantaggio dai tuoi test per sapere se sta per rompere qualche codice non documentato quando ha bisogno di cambiare o aggiungere una funzionalità.

    
risposta data 23.10.2014 - 09:41
fonte
1

Una delle strategie che ho trovato mi è stata di aiuto, specialmente se i test sono stati aggiunti dopo (potenzialmente molto tempo dopo) il codice è stato sviluppato per scrivere prima i test "component" o "integration". Questo non vuol dire che dovresti evitare i puri test unitari, ma se comprendi il comportamento del sistema (desiderato) ad un livello più alto / in un modo che sembra difficile da testare unitamente, allora inizia aggiungendo dei test che misurino il corretto funzionamento al livello che capisci.

Nel tuo caso, ad esempio, crea una Raccolta di Valutazioni o una Raccolta di Prodotti e prova alcuni filtri, setacciatura, ordinamento o qualsiasi altro metodo / operazione sono comuni a queste cose.

Sì, questo coinvolgerà più classi o moduli e non sarà un puro test unitario. E sì, dovresti tornare indietro e aggiungere test unitari per bloccare i test a livello di classe / modulo / funzione individuale. Ma partire dal livello che capisci ti porta avanti con i test e ti aiuterà a scoprire, ragionare e infine aggiungere test unitari diretti per le unità più atomiche.

    
risposta data 23.10.2014 - 17:21
fonte

Leggi altre domande sui tag