Se dovessi avere solo un'affermazione per test; come testare più ingressi?


15

Sto cercando di creare alcuni casi di test e ho letto che dovresti provare a limitare il numero di asserzioni per caso di test.

Quindi la mia domanda è: qual è il modo migliore per testare una funzione con più input. Ad esempio, ho una funzione che analizza una stringa dall'utente e restituisce il numero di minuti. La stringa può essere nella forma "5w6h2d1m", dove w, h, d, mcorrisponde al numero di settimane, ore, giorni e minuti.

Se volessi seguire il '1 asserzione per regola di test' dovrei fare più test per ogni variazione di input? Sembra sciocco, quindi invece ho solo qualcosa del tipo:

self.assertEqual(parse_date('5m'), 5)
self.assertEqual(parse_date('5h'), 300)
self.assertEqual(parse_date('5d') ,7200)
self.assertEqual(parse_date('1d4h20m'), 1700)

Nell'un caso di test. C'è un modo migliore?


Il modo migliore per farlo è utilizzare i parametri (alcuni framework supportano questa funzione, tutti i framework dovrebbero). In questo modo stai testando un singolo comportamento ma tenendo conto di molti casi di test e puoi ancora vedere quali valori dei parametri hanno causato un errore se si verifica un errore
Kemoda,

Risposte:


23

Un modo più pragmatico di visualizzare la "regola" di una sola asserzione per prova è di far sì che le tue asserzioni in una singola prova coprano un singolo concetto.

In questo modo si sta ancora testando un singolo concetto in un singolo test. Nel tuo caso, se la stringa di input viene analizzata correttamente in una singola data.

Dovresti esercitare il tuo giudizio caso per caso per verificare se stai meglio testando un singolo concetto con affermazioni multiple o avendo una singola affermazione in molti test.

Scegli l'opzione che rende più chiari i test, meno ripetizioni pur mantenendo i tuoi test in grado di evidenziare diversi punti di errore nel tuo metodo. Vuoi che sia chiaro quando un test fallisce esattamente quello che è successo invece di dover eseguire il debug del test per scoprire cosa è andato storto.


17

Dipende molto dalla tua libreria di test. Nella libreria C # NUnit puoi fare qualcosa del tipo:

[TestCase('5m', 5)]
[TestCase('5h', 300)]
[TestCase('5d', 7200)]
[TestCase('1d4h20m', 1700)]
public void ParseDateTest(inputString, expectedMinutes)
{
    Assert.That(parse_date(inputString), Is.EqualTo(expectedMinutes));
}

In java con testng hai i metodi
@DataProvider

questa è la soluzione migliore IMHO. in quasi tutte le lingue puoi parametrizzare i tuoi test. per java: @Parameterized , JunitParams , Zohhak
piotrek,

3

Sì, fai più test per ogni variazione di input.

L'obiettivo principale di un'asserzione per linea guida del test è di avere (idealmente) che un errore porta a un fallimento del test e viceversa in modo da sapere esattamente cosa non ha funzionato. Quindi puoi lavorare con un test molto preciso per eseguire il debug della causa principale e verificarlo. Puoi spezzarlo con una sola affermazione e puoi stare bene con più affermazioni. In questo particolare scenario, avrei un test per ogni suffisso e alcune combinazioni di ordinamento.

Spero che sia chiaro perché isolare i test sia un vantaggio: perdi meno tempo a eseguire il debug quando qualcosa va storto. Ora, se sei davvero sicuro che è improbabile che il test fallisca e che l'overhead della caccia attraverso il test sia piccolo, allora forse ha senso testarli tutti in una volta per risparmiare tempo di implementazione.

Ma la storia ha dimostrato che non è mai valsa la pena risparmiare un po 'di tempo a scrivere codice a spese di lettura / utilizzo del codice . Da qui la linea guida.


1

I puristi direbbero che le asserzioni per valori diversi di input dovrebbero essere inserite in metodi di test separati all'interno della classe di test. Uno dei motivi è che, a seconda dell'interfaccia utente del test, è spesso più facile distinguere tra singoli fallimenti del test piuttosto che tra singole asserzioni, il che potrebbe portarti a identificare più rapidamente la fonte del fallimento.

Durante i test con JUnit possiamo aggirare il problema utilizzando la versione dei metodi assert * con un argomento String iniziale per differenziare un'asserzione da un'altra all'interno dello stesso metodo di test.

self.assertEqual("just minutes", parse_date('5m'), 5)
self.assertEqual("just hours", parse_date('5h'), 300)
self.assertEqual("just days", ('5d') ,7200)
self.assertEqual("days, hours, minutes", parse_date('1d4h20m'), 1700)
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.