Unit Test di una funzione che produce risultati "limit less"

3

Sono piuttosto nuovo ai test unitari in un senso più sfumato. Se una funzione applicativa basata sugli input forniti dall'utente potrebbe produrre una combinazione apparente di "limit-less" di output, qual è il modo corretto di testare l'unità e quanto lontano potrebbe andare il test?

Sto pensando a qualcosa come costruire un file XML che, dato input, può creare una combinazione illimitata di file. Produrre le singole funzioni per cose come i nodi radice, i nodi figli, ecc. E testarle è piuttosto semplice per me, ma se volessi prendere tutte quelle funzioni e creare il file, come si potrebbero testare quelle combinazioni?

    
posta Shane Andrie 06.10.2015 - 23:45
fonte

3 risposte

5

Esistono due tipi di test: test della scatola nera e test della scatola bianca.

Quando esegui il test della scatola nera, non conosci le parti interne del codice che collaudi: l'unica cosa che sai è l'interfaccia e cosa il codice dovrebbe fare.

Nel test della casella bianca, puoi vedere in che modo il codice esegue effettivamente l'attività che stai per testare.

Il test unitario è un test in bianco. Ciò significa che stai facendo test unitari non basati sul numero illimitato di input e output, ma sui rami, questo è il modo possibile per eseguire il codice.

Prendiamo il seguente codice come esempio:

string sayHello(string name) {
    if (name == null) {
        return "Hello!";
    }

    return "Hello, {0}!".format(name);
}

Ci vuole un parametro che accetta un numero quasi illimitato di valori e porta a un numero quasi illimitato di risultati, e sarebbe probabilmente abbastanza problematico testare ogni combinazione. Invece, puoi esplorare il codice e testarlo in base alla logica del codice stesso:

  1. Il risultato di sayHello("Jeff") in realtà "Hello, Jeff!" ?

  2. Che dire di sayHello(null) ? È "Hello!" ?

Dopo aver provato questi casi, sei sicuro che, osservando il codice, funzionerà anche se passiamo a "Mary" o "Stephen" . Pertanto, non è necessario testare tutti i nomi che si possano immaginare.

Un altro aspetto da tenere in considerazione sono:

  • I requisiti. Ad esempio, potresti chiederti quale sarebbe l'output del metodo per una stringa vuota. Ha senso visualizzare "Hello, !" all'utente?

  • I vincoli di linguaggio, struttura e sistema. Che cosa succede se il mio nome è in realtà 2 ^ 31 - 1 caratteri di lunghezza ? Cosa accadrebbe quando il metodo chiamerà format , tentando di produrre una stringa che sia lunga 2 ^ 31 + 7 caratteri?

risposta data 07.10.2015 - 00:46
fonte
1

L'obiettivo del test unitario non è quello di testare tutte le possibilità di input rispetto a output.

L'obiettivo del test unitario è testare ogni singola regola aziendale e, nell'ambito di ciascuna regola aziendale, tutti i casi potenzialmente problematici. (Conosciuto anche come "casi limite".)

Quindi, in sostanza, se il tuo utente fornisce un pezzo di input specifico, noto in anticipo, (che è stato codificato nel test), il tuo codice produce un pezzo di output specifico, noto in anticipo (anche hard-coded nel test)?

E, se il tuo utente dà una stringa vuota, si comporta bene il tuo codice?

E, se i tuoi requisiti dicono che il tuo utente deve essere in grado di digitare fino a 10.000 caratteri, il tuo codice in effetti gestisce 10.000 caratteri? E fallisce con garbo (con un'eccezione corretta, che verrebbe in seguito tradotta in un messaggio di errore per l'utente) se l'utente fornisce 10,001 caratteri?

Inoltre, la copertura del codice è una misura di quanto è buono il tuo test unitario, non nel senso che se hai copertura del 100% del codice, allora sei a posto, ma nel senso che se hai molto meno del 100% copertura del codice allora è possibile che ti sia perso qualcosa. Quindi, usa uno strumento di copertura del codice per vedere quali parti del tuo codice non sono coperte dai tuoi test, e se qualcuna di esse è cruciale, allora costruisci un caso di test in modo tale da coprire questo pezzo di codice.

    
risposta data 07.10.2015 - 01:18
fonte
1

Il termine generale per questo tipo di test è test combinatorio .

Una tecnica comunemente usata per i test combinatori è test all-pair o pairwise , che riduce il combinatorio esplosione di casi di test cercando di trovare un insieme di casi "più interessanti". Con l'esempio della generazione di file XML con uno schema tipico, un ingenuo approccio "prova ogni opzione in combinazione" comporterebbe letteralmente milioni o miliardi di casi. I test a coppie possono probabilmente identificare alcune decine di file XML che esercitano ciascuna combinazione di funzionalità dello schema.

Un altro è un test puramente casuale o generativo, che evita lo sforzo richiesto per far bollire i casi fino al minimo stabilito semplicemente generando qualche migliaio a caso e facendo affidamento sulla legge dei grandi numeri.

Test di questo tipo potrebbero essere considerati non come test unitari. Infatti, è comunemente fatto a un livello più alto, forse da un team di test esterno. Tuttavia, se è fatto dall'autore del codice e ad un livello tecnico dettagliato, allora nella pratica non c'è molta distinzione.

Alcuni strumenti (basati su Java) per questo approccio di basso livello ai test combinatori sono jcunit , junit-quickcheck e junit-theory -Suite. La maggior parte delle altre lingue ha strumenti simili disponibili.

    
risposta data 07.10.2015 - 01:54
fonte

Leggi altre domande sui tag