Condividi tramite


Esecuzione di test

Test di diffusione

James McCaffrey

Scarica il codice di esempio

image: James McCaffreyNell'editoriale di questo mese verrà illustrata una tecnica di test del software qui denominata "test di diffusione". L'idea alla base dei test di diffusione consiste nella possibilità, a volte, di generare automaticamente nuovi dati di test case dai test esistenti in grado di generare risultati con esiti positivi.

Sebbene i test di diffusione rappresentino una tecnica non applicabile nella maggior parte degli scenari di test del software, negli altri casi consente di ottimizzare in modo significativo il livello di efficienza degli sforzi di test. Probabilmente anche perché si tratta di una tecnica di nicchia, i test di diffusione sono la meno conosciuta tra le tecniche principali di test, in base alla mia esperienza.

Prima di esporre alcuni esempi di test di diffusione, vorrei spiegare la motivazione alla base di questo metodo. Un test case è in genere costituito da un ID, un set composto da uno o più input e un risultato previsto. Il vettore {001, 2, 3, 5} può ad esempio rappresentare un test case per una funzione Sum, con ID = 001, input = 2 e 3 e risultato previsto = 5. Gli input del test case vengono inviati al sistema sottoposto a test, quindi viene prodotto un risultato effettivo confrontato con il risultato previsto per determinare un esito positivo o negativo del test case.

In molti casi di test di software è difficile e dispendioso riuscire a determinare la parte del risultato previsto di un test case. Si supponga ad esempio di testare una funziona matematica di base che calcola la media armonica di due input costituiti da due velocità. La media tra 30,0 chilometri all'ora (km/h) e 60,0 km/h non è (30,0 + 60,0)/2 = 45,0 km/h, ma la media armonica di 30,0 e 60,0, ovvero 1/((1/30,0 + 1/60,0)/2) = 40,0 km/h. La generazione di centinaia di risultati previsti per questa funzione può essere dispendiosa, prevedere tempi estremamente lunghi e produrre errori.

La difficoltà di determinare i risultati previsti dei test case è un concetto fondamentale nel test del software e a volte viene definita "problema di oracolo dei test". Un "sacro Graal" dei test di software è rappresentato dalla ricerca di tecniche in grado di determinare automaticamente test case. Pertanto, il motivo alla base dei test di diffusione risiede nel fatto che, se si riesce a generare automaticamente nuovi dati di test case, sarà possibile evitare una fase dispendiosa del processo di test e testare il sistema in modo più approfondito.

In linea di principio, la generazione automatica di dati di test case con i test di diffusione è un tecnica particolarmente efficace, ma come funziona? Di seguito viene illustrato un esempio per spiegare i test di diffusione. Si osservi la Figura 1.

image: Diffusion Testing Demo

Figura 1 Dimostrazione di test di diffusione

Viene testata una funzione, Choose(n,k), che restituisce il numero di modi per selezionare elementi k da elementi n il cui ordine non è fondamentale. Nell'esempio semplificato sono presenti tre test case. Il primo contiene gli input n = 8 e k = 3 e un risultato previsto di 56. Dopo che il test harness avrà eseguito il primo test case con un esito positivo, verrà utilizzato il test di diffusione per generare automaticamente un nuovo test case con gli input n = 9, k = 3 e un risultato previsto di 84. Niente male! Poiché il test case 002 ha generato un risultato negativo, non è stato generato un nuovo test case di diffusione.

Come vengono generati nuovi test case da quelli esistenti? Per la funzione Choose(n,k), l'espressione matematica sarà Choose(n+1,k) = Choose(n,k) * (n+1)/(n-k+1). In altre parole, esiste una relazione nota tra nuovi input e valori restituiti precedenti. La funzione utilizzata per generare un test case di diffusione da un test case esistente è illustrata nella Figura 2. L'intero programma che ha generato l'output illustrato nella Figura 1 è disponibile all'indirizzo code.msdn.microsoft.com/mag201103TestRun.

Figura 2 Generazione di un nuovo test case

static string CreateDiffusedTestCase(string existingTestCase)

{

  // Assumes input format is CaseID:N:K:Expected

  string[] tokens = existingTestCase.Split(':');



  string oldTestCase = tokens[0];

  int oldN = int.Parse(tokens[1]);

  int oldK = int.Parse(tokens[2]);

  long oldExpected = long.Parse(tokens[3]);



  string newTestCase = oldTestCase + "-diffused";

  int newN = oldN + 1;

  int newK = oldK;

  long newExpected = (oldExpected * (oldN + 1)) / (oldN - oldK + 1);



  return newTestCase + ":" + newN + ":" + newK + ":" + newExpected;

}

Per chiarire meglio l'idea, vediamo qualche altro esempio. Si supponga di testare funzioni che elaborano il seno e il coseno trigonometrici. Come da formula, sin(2t) = 2*sin(t)*cos(t). In caso di test case che generano risultati positivi per il seno e il coseno di un determinato input, sarà pertanto possibile utilizzare i test di diffusione per derivare un nuovo test case per la funzione del seno.

I test di diffusione non sono nulla di magico. Si supponga di testare una funzione che accetta un determinato ID di prodotto, esegue ricerche in un database SQL e restituisce true se il prodotto è in magazzino o, in caso contrario, false. Poiché non sussiste alcuna relazione tra input e risultati diversi, non è possibile utilizzare i test di diffusione in questo scenario. Sotto questo aspetto i test di diffusione sono simili ad altri, ad esempio i test di condizione al contorno e il pairwise testing: Si tratta di una tecnica applicabile solo in alcuni casi.

Ecco un altro esempio di test di diffusione. Si supponga di aver scritto una funzione, Gauss(z), che accetta un valore normale standard z e restituisce l'area al di sotto della distribuzione normale standard (curva a campana) da infinito negativo a z, ad esempio: Gauss(-1.645) = 0.0500, Gauss(1.645) = 0.9500 e Gauss(0) = 0.5000. Un metodo di impiego dei test di diffusione consente di notare la proprietà monotona di Gauss e determinare che per ogni valore z nell'intervallo infinito negativo/2,5 il risultato di Gauss(z + 0,1) deve essere maggiore di Gauss(z). Un altro metodo consente di notare la proprietà simmetrica di e determinare che per ogni valore z minore di 0,0 Gauss(-z) deve essere uguale a 1,0 - Gauss(z).

In questi esempi sono stati illustrati i tre scenari più comuni (ma non gli unici) in cui è possibile applicare i test di diffusione. Nel primo scenario viene testata una funzione matematica che può essere definita come relazione ricorrente, nel secondo viene testata una funzione con relazione monotona e nel terzo una funzione con relazione simmetrica. Una forma di test correlata, ma non di diffusione, è quella in cui viene testata una funzione in cui, se si inverte l'ordine dei valori di input, il valore restituito non cambia, come nel caso di Sum(x,y).

Le funzioni matematiche rappresentano il tipo più comune di componente sottoposto a test che può trarre maggiori vantaggi dai test di diffusione, in quanto queste funzioni sono spesso ricorrenti, monotone o simmetriche. È tuttavia opportuno tenere presenti anche altre situazioni. Le funzioni matematiche con relazioni ricorrenti risultano particolarmente adatte ai test di diffusione, in quanto è spesso possibile generare un numero elevato di nuovi test case da un test case esistente. Nella dimostrazione illustrata nella Figura 1 il test case 001 con n = 8, k = 3 e risultato previsto = 56 ha generato un nuovo test case di diffusione con n = 9, k = 3 e risultato previsto = 84. Questo nuovo test case può essere utilizzato per generare un altro test case con n = 10, k = 3 e risultato previsto = 120 e in caso di esito positivo può essere utilizzato per generare un nuovo test case e così via.

Prima di concludere, vorrei sottolineare un mio cruccio, relativo alla denominazione di diversi principi e tecniche di test di software. Ho definito la tecnica descritta in questo articolo "test di diffusione" poiché i test case esistenti vengono appunto "diffusi" per creare nuovi case. Avrei potuto definirla anche tecnica di test adattivi o di generazione automatica o in molti altri modi. Non è il nome che conta, ma piuttosto la tecnica che rappresenta.

In molti campi di studio, tra cui i test di software, coloro che si autodefiniscono esperti applicano un nome a una tecnica comune e tentano implicitamente di convincere i neofiti che il nome stesso ha un certo peso. Alla base di ciò risiede il desiderio di distribuire servizi di formazione (diretti) o di consulenza (indiretti) sottolineando l'importanza del nuovo nome attribuito. Sono molto gettonati i termini "test di esplorazione" e "scuola di contesto dei test", ma ce ne sono molti altri. In sostanza, "test di diffusione" è semplicemente un nome per descrivere una tecnica di test di software, ma che può rivelarsi uno strumento tecnico particolarmente utile ed efficace.

Dott. James McCaffrey* lavora in Volt Information Sciences, Inc., dove gestisce la formazione tecnica degli ingegneri software di Microsoft, presso il campus di Redmond, Washington. Si è occupato di diversi prodotti Microsoft, inclusi Internet Explorer e MSN Search. McCaffrey è autore di ".NET Test Automation Recipes" (Apress, 2006) ed è possibile contattarlo all'indirizzo jammc@microsoft.com.*

Un ringraziamento ai seguenti esperti tecnici per la revisione dell'articolo: Bj Rollison e Alan Page