Come scegliere i valori di test per i test parametrizzati per le funzioni stateless?

3

Durante la scrittura di test (parametrizzati) per le funzioni stateless, come faccio a determinare il set di valori ideale da testare con?

Sto scrivendo una classe con funzioni matematiche in C #, e voglio scrivere test unitari per loro. Oggi voglio scrivere questa funzione (davvero!):

int Clamp(int value, int lowerBound, int upperBound)
{
    // TODO: Implement.
    return 0;
}

Come impone una buona pratica del TDD, scrivo prima i test unitari e successivamente l'implementazione. Posso scrivere un test parametrizzato per questa funzione stateless, ma devo decidere il miglior insieme di valori da testare.

La mia strategia attuale per il prelievo dei valori di test è:

Per ogni parametro, posso selezionare i valori dell'intero insieme di numeri interi con segno a 32 bit. Non sto usando valori generati casualmente perché ciò renderebbe il test non ripetibile. Per verificare i casi d'angolo, seleziono -1, 0, 1, ma anche -2147483648 (numero intero con segno minimo a 32 bit) e 2147483647 (numero intero con segno massimo a 32 bit). Avrei anche bisogno di scegliere un valore 'normale', ad esempio 42, per assicurarmi che non stia solo testando i casi d'angolo. Un valore normale è sufficiente? E uno negativo, diciamo -63. Ho perso qualcuno?

−2147483648, -63, -1, 0, 1, 42, 2147483647

Se uno qualsiasi dei tre parametri può avere uno solo di questi sette valori, finirò con 343 test per una funzione ! Prima di scrivere 343 test, devo davvero chiedere:

Sono questi i valori giusti da testare? In generale, quale strategia posso usare per scegliere i valori più efficaci da usare?

    
posta Daniel Pelsmaeker 01.05.2014 - 17:49
fonte

2 risposte

1

Non hai mai detto cosa dovrebbe fare Clamp() , quindi presumo che restituisca value , a meno che non sia al di fuori dell'intervallo, nel qual caso restituisce uno dei due limiti.

Non vedo alcun motivo per pensare che -1, 0 o 1 siano casi angolari. Possono spesso essere casi d'angolo, ma non c'è ragione per cui si comporterebbero in modo strano in questa funzione. Se si desidera un valore "normale", 42 o -63 funziona, ma non è necessario per entrambi, a meno che non si sospetti che > e < non funzionino correttamente sui numeri negativi in C #. (Non penso che ti debba preoccupare per questo.)

Quindi potremmo usare solo -2147483648, 'un valore normale' e 2147483647. (Potremmo anche dire che test con i valori interi max / min non sono realmente necessari. Presumibilmente, C # > e < lavorare al minimo e al massimo, non vi è alcun pericolo di overflow di interi.)

Ci sono 6 permutazioni di 3 valori, quindi siamo in 6 casi. 6 test non è molto, e possiamo facilmente semplicemente scriverli e usarli, ma non sappiamo per certo che abbiamo selezionato casi di test che coprono tutto (tutto quello che abbiamo fatto finora è ridurre il set originale di casi di test a qualcosa di più piccolo).

Se vogliamo essere sicuri di aver individuato tutti i casi che contano, potremmo ridurre il set di valori di input (4 miliardi di cubi) in maniera massiccia dividendoli in classi di equivalenza. Quindi abbiamo solo bisogno di 1 test per classe di equivalenza, poiché la classe di equivalenza sarebbe definita come un insieme di input che agiscono tutti allo stesso modo.

Il valore di Clamp(a, b, c) dipende dal fatto che a sia compreso nell'intervallo o al di sopra o al di sotto di esso. Ci dovrebbero essere 3 classi di equivalenza: [a < b e a < c], [a > b e a > c] e in altro modo. Il valore restituito sarà b , c o a , rispettivamente. Questo ci dice non solo quali dovrebbero essere i test, ma come scrivere il codice.

(C'è una piccola cosa che non abbiamo incontrato: cosa succede se i limiti inferiori sono superiori ai limiti superiori. Ciò che ho detto nel paragrafo precedente si applica se l'ipotesi che ho inventato in alto è giusta, ma non se non lo è, ma può essere risolto facilmente, scambiando b e c o restituendo Clamp(a, c, b) se b > c.)

    
risposta data 02.05.2014 - 02:07
fonte
0

I principi Test Driven Development suggeriscono che i casi di test coprono una serie di condizioni, non solo test su un intervallo di input valido, ma anche test per la gestione delle condizioni di errore.

Quindi, inizia a testare come gestisce input non validi / validi, per vedere se gestisce correttamente l'input errato,

Questo include:

  • Semplice caso noto (PASS)
  • Semplice input "non valido" (FAIL)
  • In base al tipo di dati sottostante, i valori ai limiti per quel tipo di dati (ad esempio INT_MAX, INT_MIN, una stringa di lunghezza massima o minima che include la stringa vuota)
  • Con valori numerici, testare un valore firmato
  • Test dei valori su un intervallo completo di valori di input, oltre ciò che ha senso per l'utilizzo dell'applicazione. Se si assume che il parametro sarà normalmente compreso tra 1 e 10, come gestisce 1000000 o -10? In particolare, può essere complicato testare in modo completo il punto mobile.

L'estensività del test è determinata su fattori come il modo in cui l'uso diffuso è (cioè è un utilizzo unico al momento rispetto all'inclusione in una libreria comune), come critico sono guasti? (l'utente perde un gioco casuale contro i freni del veicolo cessano di funzionare)

If any of the three parameters can have any of just these seven values, I'll end up with 343 tests for one function! Before I'm going to write 343 tests,

Non confondere i test con i casi di test, i casi di test dovrebbero essere considerati come semplici dati.

Dovresti scrivere il codice che scorre attraverso quei casi di test che possono essere archiviati come file di testo CSV esterni e vedere se corrispondono al risultato previsto. Rompere i casi in elenchi di valori "buoni" (aspettarsi di passare) e "cattivi" (aspettarsi di fallire) e verificare semplicemente se la funzione si comporta (PASS / FAIL) come previsto fornisce la combinazione di dati di input (tutti i casi con input valido dovrebbero passare, tutti i casi con qualsiasi input non valido dovrebbero fallire), senza verificare la correttezza dell'output.

Quindi per un set o un sottoinsieme di valori di input interessanti è possibile confrontare i valori di output con i valori di output previsti , che vengono generati normalmente indipendentemente dal codice sviluppato (ad esempio per molti casi più semplici per numeri calcoli può essere usato un foglio di calcolo), assicurandosi di gestire i confronti in virgola mobile in modo sano.

Se generi automaticamente i dati del test case, il numero di casi di test diventa un fattore solo quando la velocità di esecuzione è un problema, un problema sempre più raro quando si esegue il test di funzionalità.

Nel caso della tua funzione di esempio, dove per ogni input l'output dovrebbe essere valido, puoi testare la correttezza dell'output data la particolare combinazione di valori di input.

Ti aiuta a costringere a limitare il numero di parametri a una funzione, che normalmente è una buona cosa in quanto limita le funzioni a fare bene one e non diventare un brutto mostro di speciale casi basati su tali valori aggiuntivi.

    
risposta data 01.05.2014 - 18:59
fonte

Leggi altre domande sui tag