JSCheck è un tool per il testing scritto da Douglas Crockford, uno dei massimi esperti di JavaScript, che consente di definire delle asserzioni sul comportamento previsto di una funzione generando automaticamente dei test case per la verifica.
Esistono diversi strumenti per effettuare il test di unità di codice. Anche per JavaScript esistono dei tool interessanti, come ad esempio QUnit. La maggior parte di questi strumenti, però, prevede che lo sviluppatore fornisca i dati su cui eseguire il codice da testare. Spesso questo approccio è adeguato nella verifica delle funzionalità del codice, ma in determinate situazioni sarebbe necessario fornire un elevato numero di dati per poter coprire tutte le possibili combinazioni di input.
È ad esempio il caso di routine che hanno lo scopo di verificare la correttezza di uno schema di stringhe o di valutare la robustezza di una password o di calcolare l'hash di una sequenza di byte. In tutti questi casi sarebbe utile avere uno strumento che generi automaticamente un campione di dati significativo con un elevato numero di possibili combinazioni e valuti la correttezza della nostra routine. In questi casi JSCheck può venirci incontro.
Il suo autore lo definisce un "tool per il test guidato dalle specifiche" (specification-driven testing tool), proprio a sottolineare che lo sviluppatore deve fornire soltanto le specifiche dei dati, dal momento che sarà il sistema a generare i dati su cui verranno eseguiti i test.
Il tool è implementato in un unico file, jscheck.js
, scaricabile da GitHub e prevede un unico oggetto globale JSC fornito di un ricco set di metodi per la gestione dei test.
JSCheck in azione
Per comprendere come utilizzare JSCheck prenderemo in esame una semplice funzione per la verifica formale del codice fiscale, come quella mostrata di seguito:
function controllaCF(codiceFiscale)
{
var re = /^[A-Za-z]{6}[0-9]{2}[A-Za-z]{1}[0-9]{2}[A-Za-z]{1}[0-9]{3}[A-Za-z]{1}$/;
return re.test(codiceFiscale)
}
Si tratta di una funzione semplificata che esegue soltanto una verifica sintattica del codice fiscale, senza l'analisi della validità dei vari sottocodici, ma sufficiente per i nostri scopi.
Creiamo quindi una pagina HTML ed inseriamo un collegamento a jscheck.js ed uno al file contenente la funzione da testare.
<html>
<head>
<title>JSCheck test</title>
<script src="jscheck.js"></script>
<script src="controllaCF.js"></script>
</head>
<body>
<button onclick="checkCode();">Test</button>
<div id="result"></div>
</body>
Nel corpo della pagina abbiamo inserito un pulsante che esegue la funzione checkCode()
in corrispondenza dell'evento clic ed un div che conterrà i risultati del nostro test. Questa funzione, che implementeremo nel resto dell'articolo, avrà il compito di effettuare i test di verificaCF()
sfruttando JSCheck.
Creazione di un claim
Le asserzioni in JSCheck, che definiscono il comportamento previsto per una funzione, sono chiamate claim e vengono definite tramite il metodo JSC.claim()
. Questo metodo prevede tre parametri obbligatori ed un quarto opzionale:
- una stringa che rappresenta il nome da assegnare al claim;
- il predicato, cioè una funzione booleana che stabilisce la validità di ciascun test;
- la signature, è un array che rappresenta i parametri da passare al predicato;
- classifier, opzionale, che vedremo più avanti nell'articolo. ì
Per ciascun elemento della signature verrà indicato, tramite apposite espressioni, come generare i dati su cui effettuare i test.
Cominciamo con l'analizzare la costruzione di quest'ultimo parametro, la signature. Come abbiamo detto esso è rappresentato da un array contenente un elemento per ciascun argomento da passare al predicato. Nel nostro caso avremo soltanto un elemento che rappresenta il codice fiscale. L'elemento dell'array conterrà la specifica del codice fiscale, definita sfruttando una serie di metodi di JSCheck detti specifier.
Gli specifier consentono di generare stringhe, valori numerici, valori booleani o di altro tipo in base a dei vincoli indicati dal programmatore. Ad esempio, la chiamata:
JSC.character('A','F')
restituisce un singolo carattere estratto casualmente tra A ed F, mentre:
JSC.string(4,JSC.character('A','Z'))
genera una stringa di quattro lettere maiuscole e
JSC.integer(5)
restituisce un intero da 1 a 5.
Per indicare la specifica del codice fiscale occorrerà pertanto costruire un'espressione che indica la sequenza dei caratteri previsti. Per far questo utilizzeremo la seguente espressione:
[JSC.string(
6, JSC.character('A', 'Z'),
2, JSC.integer(9),
1, JSC.character('A', 'Z'),
2, JSC.integer(9),
1, JSC.character('A', 'Z'),
3, JSC.integer(9),
1, JSC.character('A', 'Z')
)]
Essa sfrutta la possibilità di specificare sequenze di elementi come argomenti di JSC.string()
. In pratica con questa espressione stiamo descrivendo a JSCheck la struttura sintattica di un codice fiscale.
Sulla sequenza di dati generati da questa espressione verrà eseguito il predicato che si occuperà di verificare l'esito della funzione controllaCF()
:
function(verdict, CF) { return verdict(controllaCF(CF));}
Come possiamo vedere, il predicato è una funzione che si aspetta come primo parametro obbligatoriamente la funzione verdict()
ed a seguire un parametro che rappresenta ogni singolo codice fiscale generato dallo specifier. La funzione verdict() ha il compito di annunciare il risultato del test e la sua presenza rende possibile l'esecuzione di test in maniera asincrona.
Riepilogando, la definizione del nostro claim avrà la seguente forma:
JSC.claim("Verifica correttezza Codice Fiscale",
function(verdict, CF) { return verdict(controllaCF(CF));},
[JSC.string( 6, JSC.character('A', 'Z'),
2, JSC.integer(9),
1, JSC.character('A', 'Z'),
2, JSC.integer(9),
1, JSC.character('A', 'Z'),
3, JSC.integer(9),
1, JSC.character('A', 'Z')
)]);
Procediamo subito all'esecuzione del test.
Esecuzione del test
Prima di eseguire effettivamente il test occorre stabilire come visualizzare i risultati. Lo facciamo tramite la funzione JSC.on_report():
JSC.on_report( function(str) {
document.getElementById("result").innerHTML = str;
}))
Come possiamo vedere, abbiamo specificato una funzione che assegna come contenuto del div predisposto la stringa passata come parametro, che rappresenterà i risultati del test.
L'esecuzione effettiva del test verrà fatta tramite la seguente chiamata:
JSC.check();
Il risultato che vedremo a video sarà analogo al seguente:
JSCheck ha generato cento istanze di codice fiscali, le ha passate al predicato per la verifica e tutte le cento istanze hanno dato esito positivo. La cosa ci soddisfa per quel che riguarda il risultato dei test, ma sarebbe utile poter vedere le istanze generate, soprattutto nel caso di test non superati.
Organizzazione dei risultati
Vediamo dunque come poter intervenire nella visualizzazione dei risultati dei test. Avevamo parlato di un quarto parametro opzionale del metodo JSC.claim(); questo parametro, detto classifier, è proprio quello che ci serve in questo caso. Esso prevede una funzione che riceve lo stesso numero di argomenti del predicato, tranne il primo, e ci consente di organizzare l'output di ciascun test secondo le nostre necessità.
Nel caso più semplice possiamo chiedere di visualizzare ciascun dato generato dallo specifier, come mostrato di seguito:
function (CF) {return "<br>" + CF + "<br>"}
Aggiungendo questo quarto argomento alla definizione del nostro claim otterremo un risultato come quello seguente:
Tiriamo le somme su JSCheck
In conclusione, il nostro esperimento ci ha dato modo di verificare le potenzialità di JSCheck. Non è di certo uno strumento semplice ed immediato, ma individuate le caratteristiche essenziali è senz'altro utile in tutti quei casi in cui il corretto funzionamento di codice JavaScript è largamente dipendente dalla variabilità dei dati.
In questa sede ci siamo limitati a vedere le funzionalità essenziali, ma JSCheck supporta molte altre caratteristiche, come la possibilità di definire raggruppamenti di claim o di scrivere specifier personalizzati. Rimandiamo al sito del progetto per ulteriori approfondimenti.
Link Utili