Come testare i test?


53

Testiamo il nostro codice per renderlo più corretto (in realtà, meno probabilità di essere errato ). Tuttavia, anche i test sono in codice: possono contenere anche errori. E se i tuoi test sono corretti, difficilmente miglioreranno il tuo codice.

Posso pensare a tre possibili tipi di errori nei test:

  1. Errori logici, quando il programmatore ha frainteso il compito da svolgere e i test fanno quello che pensava di dover fare, il che è sbagliato;

  2. Errori nel framework di test sottostante (es. Un'astrazione beffarda che perde);

  3. Bug nei test: il test sta facendo leggermente diverso da quello che il programmatore pensa che sia.

Gli errori di tipo (1) sembrano essere impossibili da prevenire (a meno che il programmatore non diventi solo più intelligente). Tuttavia, (2) e (3) possono essere trattabili. Come gestite questi tipi di errori? Hai qualche strategia speciale per evitarli? Ad esempio, scrivi alcuni speciali test "vuoti", che controllano solo i presupposti dell'autore del test? Inoltre, come approcci il debug di un caso di test rotto?


3
Ogni pezzo introduttivo che ho letto sul deridere sembra colpire questo problema. Una volta che inizi a prendere in giro le cose, i test sembrano sempre più complicati del codice che stanno testando. Ovviamente questo è meno probabile quando si verifica il codice del mondo reale, ma è abbastanza scoraggiante quando si sta cercando di imparare.
Carson63000,

@ Carson63000 Se si tratta di un semplice qualcosa di test di prova con una testata finta, la complessità è diviso e sotto controllo (, credo).
mlvljr,

13
Ma come testare i test?
ottobre

+1. L'articolo 1 potrebbe essere un errore relativo ai requisiti. Può essere prevenuto solo rivedendo i requisiti. Probabilmente fuori dalle mani del programmatore, a meno che non siano anche l'analista dei requisiti
MarkJ,

@ocodo: allo stesso modo in cui guardi gli Osservatori. :)
Greg Burghardt,

Risposte:


18

I test sono già stati testati. I test sono protetti dalla progettazione, poiché i test rilevano solo differenze tra il codice e le nostre aspettative. Se ci sono problemi, abbiamo un errore. L'errore potrebbe essere nel codice o con la stessa probabilità nei test.

  1. Esistono alcune tecniche che ti impediscono di aggiungere lo stesso bug sia nel codice che nei test:

    1. Il client dovrebbe essere una persona diversa rispetto all'implementatore.
    2. Prima scrivi i test e poi il codice (come in Test Driven Development).
  2. Non è necessario testare la piattaforma sottostante. I test non solo esercitano il codice scritto da te, ma eseguono anche il codice dalla piattaforma. Sebbene non sia necessario catturare bug nella piattaforma di test, è molto difficile scrivere codice e test che nascondono sempre un bug nella piattaforma, in altre parole è molto difficile avere un bug sistematico in entrambi i test / codice e nella piattaforma e la probabilità viene ridotta con ogni test creato. Anche se provassi a farlo, avresti un compito molto difficile.

  3. È possibile che si verifichino dei bug nei test, ma di solito vengono rilevati facilmente perché i test vengono testati dal codice sviluppato. Tra il codice e i test hai un feedback di auto-applicazione. Entrambi fanno previsioni su come dovrebbe comportarsi una chiamata specifica di un'interfaccia. Se la risposta è diversa, non è necessario avere un bug nel codice. Potresti avere anche un bug nel test.


Risposta molto bella. Mi piace l'idea di un circuito auto-rinforzante tra i test e il codice e l'osservazione che sarebbe difficile scrivere test nascondendo costantemente i bug nella piattaforma sottostante.
Ryszard Szopa,

che non impedisce la creazione di test basati su presupposti imperfetti su cosa dovrebbe fare il codice reale. Ciò può portare a bug molto cattivi che non vengono rilevati durante i test. L'unico modo per impedirlo è quello di avere i test scritti da una terza parte senza alcuna relazione con l'organizzazione che scrive il codice reale, quindi non possono "inquinarsi" il pensiero reciproco quando si tratta di interpretare i documenti dei requisiti.
jwenting

24

Prova a rendere i singoli test il più piccolo (breve) possibile.

Ciò dovrebbe ridurre in primo luogo le possibilità di creare un bug. Anche se riesci a crearne uno, è più facile da trovare. I test unitari dovrebbero essere piccoli e specifici, con bassa tolleranza per guasti e deviazioni.

Alla fine, probabilmente è solo una questione di esperienza. Più test scrivi, migliore diventa, meno possibilità avrai di fare test scadenti.


3
Cosa succede se i test richiedono una configurazione piuttosto complicata? A volte questo genere di cose non è sotto il tuo controllo.
Ryszard Szopa,

Bene, immagino che le complicate impostazioni siano "condizioni iniziali" dei test. Se fallisce, tutti i test dovrebbero fallire. In effetti, sto lavorando a un progetto del genere in questo momento, e le persone che non hanno mai usato i test unitari hanno sempre chiesto la stessa cosa ... fino a quando non abbiamo spiegato cosa sono davvero i test unitari :) Poi si sono resi conto che può essere fatto, nonostante l'enorme complessità del progetto.
Dott. Annibale Lecter,

Qual è il modo migliore per verificare che questa "condizione iniziale" sia soddisfatta è esattamente il punto della mia domanda. Scrivi un test separato per quello? Oppure supponi che i test si interrompano se questa condizione non è vera? Che dire della situazione in cui l'installazione non è "catastroficamente" male, solo leggermente spenta?
Ryszard Szopa,

2
I test dovrebbero fallire se le condizioni iniziali non sono giuste, questo è il punto. Quando Asei nello stato , ti aspetti un risultato B. Se non si dispone di uno stato A, un test dovrebbe fallire. A quel punto è possibile verificare perché non ha funzionato correttamente, condizioni iniziali errate o test errati, ma in entrambi i casi dovrebbe fallire. Anche se è, come dici tu, "un po 'fuori" (vale a dire "A" => "B", "a" => "b"ma mai "a" => "B"o il test è male).
Dott. Annibale Lecter,

19

Una tattica è scrivere il test prima del codice che verifica e assicurarsi che il test fallisca prima per la giusta ragione. Se usi TDD dovresti ottenere almeno questo livello di test dei test.

Un modo più esauriente per testare la qualità di una suite di test consiste nell'utilizzare il test di mutazione .


2
E che il tuo test fallisce per la giusta ragione .
Frank Shearar,

@Frank - Sì. Lo aggiungerò alla risposta.
Don Roby,

E stai aggiungendo un nuovo test per il nuovo comportamento da testare. Non aggiungere ai test esistenti.
Huperniketes

@DonRoby, hai trovato utile il test di mutazione in pratica? Quali carenze hai riscontrato nei tuoi casi di test con questo?
dzieciou,

4

Per # 1 e # 3: i test unitari non devono contenere alcuna logica, se lo fai probabilmente stai testando più di una cosa nel test unitario. Una best practice per i test unitari è quella di avere un solo test per test unitario.

Guarda questo video di Roy Osherove per saperne di più su come scrivere bene i test unitari.


annuncio n. 3 - Concordo sul fatto che i test dovrebbero essere il più semplici possibile e non dovrebbero contenere alcuna logica. Tuttavia, pensa alla fase di installazione del test, quando crei gli oggetti di cui avrà bisogno. È possibile creare oggetti leggermente sbagliati. Questo è il tipo di problemi a cui sto pensando.
Ryszard Szopa,

Quando dici "oggetti leggermente sbagliati", intendi che lo stato dell'oggetto non è corretto o il disegno reale dell'oggetto non è corretto? Per lo stato dell'oggetto, è possibile che si verifichino test per verificarne la validità. Se la progettazione è errata, il test dovrebbe fallire.
Piers Myers,

3

In termini di # 1 - Penso che sia una buona idea accoppiare / rivedere il codice per questo lato delle cose. È facile fare presupposti o semplicemente sbagliare, ma se devi spiegare cosa sta facendo il tuo test, qual è il punto, è più probabile che tu raccolga se stai mirando al bersaglio sbagliato.


2

Ci deve essere un punto in cui si dovrebbe smettere di provare a unit test. Dovrebbe sapere quando disegnare la linea. Dovremmo scrivere casi di test per testare casi di test? Che dire dei nuovi casi di test scritti per testare casi di test? Come li testeremo?

if (0 > printf("Hello, world\n")) {
  printf("Printing \"Hello, world\" failed\n");
}

Modifica: aggiornato con spiegazione come suggerito dal commento.


-1 Cosa? Questo sembra non avere rilevanza.
alternativa

2
Ci deve essere un punto in cui si dovrebbe smettere di provare a unit test. Dovrebbe sapere quando disegnare la linea. Dovremmo scrivere casi di test per testare casi di test? Che dire dei nuovi casi di test scritti per testare casi di test? Come li testeremo?
aufather,

2
Process Brain ha sollevato EInfiniteRecursion mentre tentava di estrapolare la tua dichiarazione ...
Mason Wheeler,

Sostituisci la tua risposta con il tuo commento e otterrai un +1
Nota per te stesso - pensa a un nome

3
In tutta onestà, il tuo esempio è un uomo di paglia. Stai testando il sottosistema printf () in una libreria C, non il programma reale che chiama printf (). Concordo, tuttavia, sul fatto che ad un certo punto si debba interrompere il test ricorsivo dei test.
Tim Post

2

Hey.
Devi applicazioni:

  • Il tuo prodotto
  • Il tuo test per quel prodotto.

Quando si eseguono test sul prodotto, in realtà non si è interessati al test stesso, ma all'interazione tra il prodotto e i test. Se il test fallisce non dice che l'applicazione ha un bug. Dice che l' interazione tra prodotto e test non ha avuto successo . Ora tocca a te determinare cosa è andato storto. Può essere:

  • l'applicazione non si sta comportando come previsto (questa aspettativa è espressa nel test)
  • l'applicazione si sta comportando correttamente, non hai documentato correttamente questo comportamento (nei tuoi test)

Per me i test falliti non sono semplici feedback, che questo e quello sono sbagliati . È un indicatore della presenza di incoerenze e devo esaminare entrambe per verificare se il problema è andato storto. Alla fine sono responsabile della verifica che l'applicazione sia corretta, i test sono solo uno strumento per evidenziare le aree che potrebbero valere la pena di essere verificate.

I test stanno verificando solo alcune parti dell'applicazione. Collaudo l'applicazione, collaudo i test.


2

I test non dovrebbero essere abbastanza "intelligenti" per ospitare i bug.

Il codice che stai scrivendo implementa una serie di specifiche. (Se X allora Y, a meno che Z nel qual caso Q, ecc. Ecc.). Tutto il test che dovrebbe tentare di eseguire è determinare che X sia davvero Y a meno che Z nel qual caso Q. Ciò significa che tutto un test dovrebbe essere fatto impostando X e verificando Y.

Ma questo non copre tutti i casi, probabilmente stai dicendo, e avresti ragione. Ma se rendi il test abbastanza "intelligente" da sapere che X dovrebbe solo con Y se non Z, allora stai sostanzialmente implementando nuovamente la logica di business nel test. Questo è problematico per ragioni che approfondiremo un po 'più in basso. Non dovresti migliorare la copertura del codice rendendo il tuo primo test "più intelligente", devi invece aggiungere un secondo test stupido che imposta X e Z e verifica Q. In questo modo avrai due test, uno che copre il caso generale ( a volte noto anche come il percorso felice) e uno che copre il caso limite come un test separato.

Ci sono una serie di ragioni per questo, innanzitutto come si determina se un test fallito è dovuto a un bug nella logica aziendale o a un bug nei test? Ovviamente la risposta è che se i test sono il più semplici possibile è molto improbabile che siano presenti bug. Se ritieni che i tuoi test debbano essere testati, stai sbagliando .

Altre ragioni includono il fatto che stai solo replicando gli sforzi (come ho già detto, scrivere un test abbastanza intelligente da esercitare tutte le possibilità in un singolo test sta sostanzialmente replicando la logica aziendale che stai provando a testare in primo luogo), se i requisiti cambiano quindi i test dovrebbero essere facili da modificare per riflettere i nuovi requisiti, i test servono come una sorta di documentazione (sono un modo formale per dire quali sono le specifiche dell'unità sotto test) e così via.

TL: DR: se i tuoi test hanno bisogno di essere testati, stai sbagliando. Scrivi test stupidi .


0

Non una risposta (non ho il privilegio di commentare), ma mi chiedevo se hai dimenticato altri motivi per lo sviluppo di casi di test ...
Una volta individuati tutti i bug nei test, puoi regredire facilmente testando la tua applicazione. Le suite di test automatizzate ti aiuteranno a trovare i problemi prima, prima dell'integrazione. Le modifiche ai requisiti sono relativamente più facili da testare, poiché le modifiche possono diventare più recenti, versione modificata dei casi di test precedenti che passano e i casi più vecchi rimangono per raccogliere errori.


0

Risposta breve: il codice di produzione verifica i test .

Confronta questo con il modello di credito / debito utilizzato in economia. I meccanismi sono molto semplici: se il credito differisce dal debito, c'è qualcosa che non va.

lo stesso vale per i test unitari - Se un test fallisce indica che qualcosa non va. Potrebbe essere il codice di produzione, ma potrebbe anche essere il codice di prova! Quest'ultima parte, se importante.

Nota che i tuoi bug di tipo (1) non possono essere trovati dai test unitari. Per evitare questo tipo di bug hai bisogno di altri strumenti.

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.