Quanto dovrei interrompere i miei test unitari?

2

Recentemente ho appreso dei test unitari e TDD e ho iniziato a tornare ad aggiungere test unitari al mio codice (e grazie a Dio, è provato che alcune cose che ho scritto sono molto più rotte di quanto pensassi).

Detto questo, sto facendo fatica a capire quanto (o poco) dovrebbe andare in ogni test. Ad esempio, considera una classe che ho scritto con diversi metodi. In questo momento faccio qualcosa di simile

class test_myclass(unittest.TestCase):

    def setUp(self): 
        ...
    def test_func1(self):
        ...
    def test_func2(self):
        ...
    etc
    def tearDown(self):
        ...

Ma cosa succede se ogni metodo (o almeno alcuni) può fallire in molti modi diversi o ha molti casi limite? Quindi sono bloccato a fare qualcosa di simile

def test_func1(self):
    self.assertEqual(func1(working_input), expected_value)
    self.assertRaises(Some_error, func1, args)
    self.assertRaises(Some_other_error, func1, args)
    etc

E potrebbe diventare piuttosto peloso, e piuttosto poco chiaro dove le cose stanno fallendo. Quindi ho pensato che avrei potuto suddividerlo di più e dedicare una classe a ciascuna funzione (che ha abbastanza casi di test per valerne la pena), ma mi sembra che ci sia un sacco di lavoro e più tempo di quanto dovrei spendere per i test. / p>

Ho anche considerato di scrivere più test per un determinato metodo, come

def test_func1(self):
    self.assertEqual(func1(working_input), expected_val)
def test_func1_bad_input_1(self):
    self.assertRaises(error, func1, bad_args)
def test_func1_bad_input_2(self):
    self.assertRaises(error2, func1, bad_args_2)
...

E questo sembra più pulito di una classe di test unitario per metodo, ma sembra ancora che potrebbe essere troppo scarso in ogni dato test.

Quanto test è troppo?

Mentre il mio esempio è stato fornito in python, sono aperto alle risposte agnostiche della lingua

    
posta Dannnno 25.10.2014 - 04:03
fonte

3 risposte

10

In un mondo ideale, un test di una singola unità ha solo una cosa che può causarne il fallimento e una cosa può solo causare che quel test fallisca.

Non sono sicuro di averlo mai visto così ... Un approccio più raggiungibile è che un test di una singola unità verifica un singolo percorso attraverso una funzione. Il concetto di copertura del codice è utile qui, ma il succo è che qualsiasi decisione presa dal tuo codice rappresenta (almeno) un percorso diverso. Alcuni percorsi possono essere troppo difficili (o addirittura impossibili) per il test unitario, ma questo è il livello di granularità verso cui lavorare.

Il vantaggio è che quando un test fallisce, passi meno tempo e fatica a capire perché .

E sì, sembra un po 'più di lavoro, ma una volta che ci sei abituato, i test sono veloci e facili da scrivere e ti faranno risparmiare un sacco di tempo.

    
risposta data 25.10.2014 - 04:46
fonte
2

Si lotta perché non si sta facendo TDD - al momento si aggiungono i test unitari successivamente invece di prima. Usare TDD "dal libro" significa: lavorare con cicli estremamente brevi di

  • pensa al prossimo requisito / cambiamento che desideri implementare
  • scrivi un test esattamente per quel requisito
  • esegui il test (ti dà in genere "rosso")
  • implementa una modifica per il requisito
  • esegui di nuovo il test (speriamo in verde, correggi il codice se non è "verde")
  • refactor (codice e test)

Quando lavori in questo modo, la risposta alla tua domanda "Quanto test è troppo?" diventa ovvio: scrivi esattamente la quantità di test necessari per assicurarti che la prossima funzionalità o la modifica della tua classe o funzione funzioni come previsto - né più né meno.

TDD è meno un test, ma più una tecnica di implementazione . La scrittura dei test e l'implementazione del codice sono completamente intrecciati. Una volta implementata una funzionalità o una modifica, è necessario aver già scritto la maggior parte dei test in anticipo per garantire che la funzionalità funzioni come previsto, quindi quando la funzione è "pronta", non ci sono test da scrivere più. Quando ritieni di aver perso alcuni casi limite e non sei sicuro che la tua funzione li gestisca correttamente, quindi aggiungi alcuni test aggiuntivi in seguito. Ma questo potrebbe anche essere un segno dell'attuazione di troppe cose contemporaneamente - meglio aggiungere prima un test e il codice per il "percorso felice", poi aggiungere il test e il codice che si occupa di quel caso limite - esattamente nell'ordine indicato.

In uno scenario del mondo reale, lavorare sempre in quel modo potrebbe essere troppo idealistico, ma una volta compreso il significato di TDD, la domanda "quanto ai test per scrivere" è molto più facile da rispondere.

Una volta capito il numero di test che devi veramente scrivere, la domanda su come suddividerli è molto più facile da rispondere: li rompi (nella fase di refactoring sopra) finché non pensi al design e alla struttura dei test hai scritto finora è abbastanza buono. I principi SOLID sono una buona guida non solo per il tuo codice di produzione, ma anche per i tuoi test. Ad esempio, se si dispone di un solo test per una funzione, una singola funzione di test va bene. Quando scopri di aver bisogno di più test per la stessa funzione, potrebbe esserci il punto in cui hai bisogno di una classe completa di test solo per una singola funzione.

    
risposta data 25.10.2014 - 17:36
fonte
1

I test unitari ti danno valore e creano lavoro. Vuoi il miglior valore possibile per il lavoro.

Se scrivi dieci test ciascuno controllando dieci articoli, invece di 100 test ciascuno controllando un oggetto di solito un po 'di lavoro. Hai ancora la stessa copertura di test. Quindi se i tuoi test funzionano, stai bene. Se falliscono, e tu lo ignori, stai anche bene.

Nel caso in cui si abbia un test non funzionante e in realtà lo si risolva, si ha un po 'di lavoro per capire quale oggetto ha avuto esito negativo, poi qualche lavoro per capire perché ha fallito e qualche altro lavoro per risolverlo. Direi che di solito il risparmio che si ha dal sapere quale di 100 articoli è fallito rispetto a quale gruppo di dieci elementi è fallito è minimo. Di solito è più che compensato dal risparmio di tempo che hai durante la scrittura dei test.

    
risposta data 23.06.2015 - 18:48
fonte

Leggi altre domande sui tag