Quanto dovrebbero essere granulari i test TDD?

18

Durante l'addestramento TDD basato su casi di software medico stiamo implementando la seguente storia: "Quando l'utente preme il pulsante Salva, il sistema dovrebbe aggiungere paziente, aggiungere dispositivo e aggiungere record di dati dispositivo".

L'implementazione finale sarà simile a questa:

if (_importDialog.Show() == ImportDialogResult.SaveButtonIsPressed)
{
   AddPatient();
   AddDevice();
   AddDeviceDataRecords();
}

Abbiamo due modi per implementarlo:

  1. Tre test in cui ognuno verifica un metodo (AddPatient, AddDevice, AddDeviceDataRecords) chiamato
  2. Un test che verifica tutti e tre i metodi chiamati

Nel primo caso se succede qualcosa di sbagliato in condizione di clausola, tutti e tre i test falliranno. Ma nel secondo caso se il test fallisce, non siamo sicuri di cosa sia esattamente sbagliato. In che modo preferiresti.

    
posta SiberianGuy 23.09.2011 - 10:11
fonte

5 risposte

8

But in the second case if test fails, we are not sure what is exactly wrong.

Penso che dipenderebbe in gran parte da quanto buoni messaggi di errore il test produce. In generale, ci sono diversi modi per verificare che sia stato chiamato un metodo; per esempio. se usi un oggetto fittizio, ti darà un preciso messaggio di errore che descrive quale metodo previsto non è stato chiamato durante il test. Se verifichi che il metodo è stato chiamato rilevando gli effetti della chiamata, spetta a te generare un messaggio di errore descrittivo.

In pratica, la scelta tra le opzioni 1 e 2 dipende anche dalla situazione. Se vedo il codice che mostri in un progetto precedente, scelgo l'approccio pragmatico del caso n. 2 solo per verificare che ciascuno dei 3 metodi sia chiamato correttamente quando la condizione è soddisfatta. Se sto sviluppando questo pezzo di codice in questo momento, le 3 chiamate al metodo verrebbero probabilmente aggiunte una alla volta, in momenti separati (probabilmente a giorni o mesi di distanza l'una dall'altra), quindi aggiungerei un nuovo test dell'unità separato per verificare ogni chiamata.

Nota anche che in entrambi i casi, dovresti anche avere test unitari separati per verificare che ognuno dei singoli metodi faccia ciò che dovrebbe fare.

    
risposta data 23.09.2011 - 10:18
fonte
30

La granularità nel tuo esempio sembra essere la differenza tra i test di unità e di accettazione.

Un test unittest una singola unità di funzionalità, con il minor numero possibile di dipendenze. Nel tuo caso, potrebbero esserci 4 unittests

  • AddPatient aggiunge un paziente (ad esempio chiama le funzioni del database pertinenti)?
  • AddDevice aggiunge un dispositivo?
  • AddDeviceDataRecords aggiunge i record?
  • fa la funzione principale unamend nel tuo esempio chiama AddPatient, AddDevice e AddDeviceFunctions

Le Unittests sono per gli sviluppatori , quindi ottengono confidenza, che il loro codice è tecnicamente corretto

I test di accettazione dovrebbero testare la funzionalità combinata, dal punto di vista dell'utente. Dovrebbero essere modellati lungo le storie degli utenti e essere il più alto possibile. Pertanto, non è necessario verificare se le funzioni vengono chiamate, ma se si ottiene un vantaggio visibile all'utente :

quando l'utente inserisce i dati, fa clic su OK e ...

  • ... va all'elenco dei pazienti, dovrebbe vedere un nuovo paziente con il nome specificato
  • ... va all'elenco dei dispositivi, dovrebbe vedere un nuovo dispositivo
  • ... va ai dettagli del nuovo dispositivo, dovrebbe vedere nuove datarecords

I test di accettazione sono per i clienti o, per costruire una comunicazione migliore con loro.

Per rispondere alla tua domanda "cosa preferiresti": che problema ti è più grande adesso, bug e regressione (= > più unittests) o comprensione e formalizzazione del quadro generale (= > più test di accettazione)

    
risposta data 23.09.2011 - 10:41
fonte
13

We have two ways to implement it:

Questo è falso.

Three tests where each verifies one method (AddPatient, AddDevice, AddDeviceDataRecords) was called

Devi devi farlo per essere sicuro che funzioni.

One test which verifies all three methods were called

Devi anche fare questo per assicurarti che l'API funzioni.

La classe - come unità - deve essere completamente testata. Ogni metodo.

Puoi iniziare con un test che copre tutti e tre i metodi, ma non ti dice molto.

if test fails, we are not sure what is exactly wrong.

Una corretta. Ecco perché provi i tutti i metodi .

Tu devi testare l'interfaccia pubblica. Poiché questa classe fa tre più cose (anche se sono raggruppate in un unico metodo a causa della trama dell'utente) è necessario testare tutte e quattro le cose. Tre livelli bassi e un pacchetto.

    
risposta data 23.09.2011 - 11:53
fonte
2

Scriviamo i nostri test unitari per frasi significative di funzionalità che molte volte mappano su un metodo (se hai scritto bene il tuo codice), ma a volte diventano più grandi, comprendendo molti metodi.

Ad esempio, immagina che l'aggiunta di un paziente al tuo sistema abbia bisogno di alcune subroutine (funzioni figlio) da chiamare:

  1. VerifyPatientQualification
  2. EnsureDoctorExistence
  3. CheckInsuranceHistory
  4. EnsureEmptyBed

Potremmo anche scrivere test di unità per ognuna di queste funzioni.

    
risposta data 23.09.2011 - 22:19
fonte
2

Una semplice regola empirica che ho seguito è quella di nominare il test in modo che descriva esattamente cosa fa il test. Se il nome del test diventa troppo complesso, è un segno che il test sta forse facendo troppo. Quindi, ad esempio, nominare un test per fare ciò che si propone nell'opzione 2 può sembrare PatientIsAddedDeviceIsAddedAndDeviceDataRecordsWhenSaved che è molto più complesso di tre test separati. PatientIsAddedWhenSaved, DeviceIsAddedWhenSaved, DataRecordsWhenSaved. Penso anche che le lezioni che possono essere apprese dal BDD sono piuttosto interessanti dove ogni test è realmente rappresentativo di un singolo requisito che potrebbe essere descritto in un linguaggio naturale. In questa ottica mi piace l'idea di passare una lista dei nomi dei test a un non sviluppatore per verificare che abbiamo coperto tutti i requisiti necessari, quindi ogni volta che un singolo test diventa troppo intimidatorio in termini di verbosità, penso che sia un ottimo motivo per considerare la rottura i test.

    
risposta data 23.07.2012 - 21:32
fonte

Leggi altre domande sui tag