La scrittura efficace unit test Javascript con YUI test
5 gennaio 2009 alle 10:38 da Nicholas C. Zakas | In Sviluppo | 6 commentiUno dei più grandi sotto-il-radar movimenti in JavaScript sviluppo nel corso del 2008 è stato il riemergere di un interesse per unit testing. YUI test , test YUI quadro di unità, ha raggiunto lo status GA a febbraio e altre biblioteche sia introdotto proprio framework di test unità o avviato pubblicizzare quelli già esistenti. Come risultato, c'è molta più documentazione riguardante la creazione di unit test per JavaScript. Basta avere gli unit test JavaScript non è sufficiente, però, se i test sono scritti in modo improprio, possono portare ad un sacco di tempo perso. Imparare a scrivere efficace unit test JavaScript vi farà risparmiare tempo e mal di testa nel futuro.
Cosa stai test?
La chiave per la scrittura di unit test efficace è quello di comprendere la parola "unità". In termini di prova, una unità è una parte isolata di codice che può essere testata indipendente da altri pezzi di codice. In un linguaggio orientato agli oggetti come JavaScript, ogni metodo è considerato come una unità. La corretta progettazione OO comporta tipicamente metodi ben incapsulato che servono un unico scopo e sono quindi facili da testare.
Test delle unità tradizionali è stato progettato per testare l'implementazione di un'interfaccia, in modo da metodi privati non fare il test in modo esplicito. Questo si chiama test black box. L'idea è che si può scambiare l'implementazione di un'interfaccia e il test di unità saranno tutti ancora passare perché sono completamente agnostico per l'implementazione sottostante. Tutti i test che so è un insieme di vincoli che devono essere soddisfatti, perché non importa quanto questi vincoli sono soddisfatti.
Prove di scrittura
Come ho detto nel mio discorso, unit test dovrebbe testare gli ingressi e le uscite. Gli ingressi possono essere nominato argomenti dei metodi o cambiamenti nelle variabili globalmente accessibile che il metodo dipende per funzionare correttamente. Uscite possono essere i valori di ritorno, i cambiamenti nello stato di variabili, e gli errori anche gettato. Per ogni set di input-output, ci dovrebbe essere una prova singola unità. Ogni test deve esplicitamente, "dato questi ingressi, mi aspetto che queste uscite". Ogni deviazione da questa affermazione è un test fallito.
Ogni test deve essere il più semplice possibile e prova un solo set di input-output, che combina set in un singolo test riduce l'efficacia dei test di unità. Per esempio, si consideri il seguente test di una funzione chiamata trim() :
var = new testCase YAHOO.tool.TestCase ({ nome: "trim () Test", testTrim: function () { risultato1 var = trim ("Ciao mondo"); YAHOO.util.Assert.areEqual ("Ciao mondo", risultato1, "Leading spazio bianco dovrebbe essere spogliato."); risultato2 var = trim ("Ciao mondo"); YAHOO.util.Assert.areEqual ("Ciao mondo", result2, "Trailing spazio bianco dovrebbe essere spogliato."); } });
Qui, il testTrim() metodo del test case è in realtà due diversi test di ingresso-uscita definisce:
- Stringa di input ha spazi bianchi; valore di ritorno non ha spazio iniziale bianca.
- Stringa di input è spazio bianco; valore di ritorno non ha spazi vuoti finali.
Il problema è che questi due set hanno letteralmente alcuna relazione tra loro, ma se il primo input-output set non riesce a produrre il risultato corretto, il secondo non sarà mai testato. Questa è una situazione in cui una delle maschere un altro fallimento. E 'più efficace di separare questi input-output set in due prove:
var = new testCase YAHOO.tool.TestCase ({ nome: "trim () Test", testTrimWithLeadingWhiteSpace: function () { var result = trim ("Ciao mondo"); YAHOO.util.Assert.areEqual ("Ciao mondo", risultato "Leading spazio bianco dovrebbe essere spogliato."); }, testTrimWithTrailingWhiteSpace: function () { var result = trim ("Ciao mondo"); YAHOO.util.Assert.areEqual ("Ciao mondo", risultato "Trailing spazio bianco dovrebbe essere spogliato."); } });
Questo codice ora i test correttamente il trim() la funzione di input-output set, tenendole separate.
I test unitari sono sempre scritte come se il codice in fase di test funziona correttamente. Buona progettazione del software comporta mappatura questi input-output set prima del tempo in modo da sapere esattamente che cosa il risultato dovrebbe essere in ogni caso. In questo modo, gli unit test diventare un tipo di documento requisiti tecnici in aggiunta al codice vero e proprio.
Asserzioni efficace
Una delle parti più importanti della scrittura di unit test è la definizione affermazione corretta. Ogni asserzione specifica una condizione che, se non soddisfatte, indica che la funzionalità non è un comportamento corretto. E 'importante utilizzare solo come affermazioni quante sono necessarie per testare correttamente il codice di uscita. Troppe affermazioni possono portare a falsi errori, mentre troppo pochi possono portare a passi falsi.
Nell'esempio precedente, ogni test contiene una affermazione solo perché questo è tutto ciò che serve. So esattamente il valore che deve essere restituito e quindi ho prova specificamente per questo. I test possono entrambi sembrare molto semplice, ma ottengono il lavoro fatto. Anche in questo caso, non c'è una regola sul numero di affermazioni che fanno un buon test, assicuratevi che stai provando ogni uscita prevista del codice per l'ingresso.
Per rendere fallimenti dei test più coerente, si dovrebbe includere un messaggio di errore ad ogni asserzione. Nel test YUI, questo è sempre l'ultimo argomento di ogni metodo di affermazione. Un messaggio di errore dovrebbe dire che cosa dovrebbe essere accaduto, non ciò che è accaduto. Alcuni esempi:
/ / Bad fallimento messaggio YAHOO.util.Assert.areEqual ("Ciao mondo", risultato: "Il risultato non è stato 'Ciao mondo'"); / / Buona messaggio di errore: YAHOO.util.Assert.areEqual ("Ciao mondo", risultato "Leading spazio bianco dovrebbe essere spogliato.");
Si noti la differenza tra il messaggi di errore cattivi e buoni: i cattivi ti dice cosa è successo e il bene ti dice quanto ci si aspettava. Quando si esegue il test, un fallimento indica già che qualcosa di imprevisto è accaduto, quindi non c'è bisogno di ripetere semplicemente che qualcosa di imprevisto è accaduto. E 'più utile sapere che cosa sarebbe dovuto accadere, perché è una rappresentazione esatta della vostra esigenza. Con questo approccio, i guasti finiscono per essere un elenco di esigenze insoddisfatte che si può tornare più e valutare.
Lavorare con il DOM
JavaScript è unica ad altre lingue, in quanto ha spesso legami con l'ambiente, il DOM. I metodi che interagiscono pesantemente con il DOM sono difficili da unit test, perché l'intero ambiente deve essere impostato in modo che il metodo da eseguire completamente. Complicare ulteriormente le cose è la tendenza di JavaScript per essere scatenata da un'azione dell'utente come ad esempio un clic del mouse. YUI test fornisce la simulazione di eventi per aiutare nella creazione di test per i metodi che dipendono dalla interazione DOM, però, questa comincia ad attraversare nella zona di test funzionali.
Collaudo funzionale, al contrario di unit test, è progettato per testare l'esperienza dell'utente con il prodotto piuttosto che di input-output set per il codice. Se vi trovate a voler verificare che l'interfaccia utente risponde in modo specifico a causa di interazione con l'utente, allora davvero si vuole scrivere alcuni test funzionali, piuttosto che gli unit test. YUI test può essere usato per scrivere alcuni test funzionali di base, ma il più popolare (e piuttosto bene) lo strumento di tali test è Selenio .
Il modo migliore per determinare se qualcosa è uno unit test è quello di chiedere se può essere scritto prima del codice che è stato progettato per testare effettivamente esiste. Test di unità, come parte del test-driven development, sono in realtà dovrebbe essere scritto davanti al codice vero e proprio come un modo per orientare gli sforzi di sviluppo. Test funzionali, d'altra parte, non può esistere prima del tempo perché sono così legati all'interfaccia utente e come cambia in risposta all'interazione dell'utente.
Strutturazione delle gerarchie prova
YUI prova, così come altri framework test di unità, supporta una gerarchia di casi di test e di suite di test. Ogni suite di test può contenere altre suite di test e test case, casi di test possono contenere solo i test attuali (metodi che iniziano con la parola "test"). Il modo migliore di organizzare la gerarchia di prova è quello di seguire uno schema molto semplice:
- Creare una suite di test per ogni oggetto che si vuole testare.
- Creare un banco di prova per ogni metodo di un oggetto che si vuole testare e aggiungerlo alla suite di test dell'oggetto.
- Creare un test per ogni banco di prova per ogni input-output set.
In questo modo, la gerarchia di test rispecchia il codice che si sta testando ed è più facile capire dove nuovi test deve essere creato.
Eseguire il test!
Forse la parte più importante del test di unità è quello di eseguire i test di frequente. Test è efficace solo se fatto su una base regolare. Come minimo, si dovrebbe eseguire unit test prima di archiviare modifiche controllo del codice sorgente. In modo ottimale, devi anche eseguire il test in modo automatico su base regolare per convalidare le modifiche dopo che sono stati impegnati a controllo del codice sorgente. Questo è il modo si otterrà il più grande vantaggio di unit testing: discernimento veloce, e si spera di prevenzione, di regressioni.
Ulteriori informazioni
- YUI test
- YUI Teatro: Test Driven Development con YUI di prova, da Nicholas C. Zakas
- FireUnit
- Estensione FireUnit per YUI test
- JavaScript è troppo Codice: Test It!
- JavaScript Unità prova di isolamento
Condividere ed estendere: Bookmark with del.icio.us | Digg it! | reddit!
6 commenti
Al momento l'inserimento di commenti non è in questo momento.

Copyright © 2006-2012 Yahoo! Inc. Tutti i diritti riservati. Privacy Policy - Termini del Servizio
Powered by WordPress su Yahoo! Web Hosting .

Sono le prove YUI eseguito automaticamente a intervalli regolari? Se è così puoi condividere qualsiasi informazione su come si esegue questa operazione? Sono particolarmente interessato a come si tratta con la deposizione delle uova e la chiusura del browser processi utilizzati per eseguire i test in corso di una generazione automatica, e anche il modo di raccogliere e aggregare i risultati dei test per la compilazione.
Commento di Simon - 5 gennaio 2009 #
La soluzione migliore che ho visto thusfar è quello di utilizzare Selenio per gestire il ciclo di vita del browser per il test. È possibile impostare fino a eseguire periodicamente e quindi monitorare la pagina dei risultati.
Commento di Nicola Zakas C. - 7 GENNAIO 2009 #
Prima di tutto, grazie per aver scritto questo post meraviglioso blog. Vorrei commentare quanto segue:
Personalmente preferisco pensare a una classe come unità. La classe mi fornisce alcuni comportamenti e voglio spiegare che il comportamento attraverso i miei test. Andando ad un livello metodo sembra che siamo foratura nella realizzazione in un certo senso.
Io preferirei se si qualifica il tuo stile di unit testing come unit testing stato basato. C'è una scuola diversa di unit testing che crede nei test di interazione basato. Se le sue non tanto il risultato in termini di valori di ritorno, i cambiamenti nello stato di variabili, o errori generati. L'attenzione si concentra sull'interazione (chiamate metodo) con il suo collaboratori.
Sembra che abbiano rotto la convenzione xUnit. nel messaggio di errore xUnit è sempre il primo argomento.
Lei afferma:
Mentre concordo con lei che il secondo esempio è meglio del primo, ma penso che il messaggio di errore nel secondo caso è ridondante. Se si guarda al metodo di prova tutta di seguito,
testTrimWithLeadingWhiteSpace: function(){var result = trim(" Hello world");
YAHOO.util.Assert.areEqual("Hello world", result, "Leading white space should be stripped.");
}
Il nome del metodo indica già che spazi bianchi dovrebbero essere tagliate o rimosse. In questo caso specifico non darei alcun messaggio di errore. Se le migliori prassi sua propria azienda di dare uno, poi io preferisco il tuo messaggio di errore come "Leading spazio bianco non è stato spogliato"
Questo non è sempre vero. In molti casi si può effettivamente scrivere il test funzionali o di accettazione prima di creare qualsiasi codice. Fare riferimento al test di sviluppo accettazione Driven
Perché è importante? Io non vedo come questo aiuterà?
Io preferirei creare una classe di test per entità importante nel mio codice di produzione e scrivere un metodo di prova per il comportamento della classe soddisfa. A volte avrei potuto più di 1 prova per un metodo e, a volte nessuno. Non so se mi avrebbe creato una linea guida dice ogni metodo deve avere un test.
Commento di Naresh Jain - 11 Gen, 2009 #
Ciao Naresh,
Grazie per i vostri commenti illuminanti. Infatti, ci sono molte scuole di pensiero che circonda metodologia di prova, e hai toccato alcuni di loro. Vorrei solo chiarire un paio di punti.
Rendere il messaggio di errore di asserzione una dichiarazione di ciò che dovrebbe accadere non è ridondante, è esplicativo di ciò che è appena accaduto. Il nome del test e il messaggio di errore potrebbe essere simile, e in questo caso sono perché il test è così semplice, tuttavia, possono essere molto diversi se ci sono una serie di affermazioni contenute nel test.
La mia raccomandazione per la creazione di suite di test e test case è quello di ottenere la gente ha iniziato. Non sto dicendo che ogni metodo deve essere un test, sto dicendo che ogni metodo deve avere un banco di prova che contiene i test che esplorano ogni input-output set che si hanno. Il punto è di avere una struttura logica che le mappe direttamente agli oggetti che si sta programmando.
Spero che questo chiarisce alcuni dei punti, grazie per i vostri commenti.
Commento di Nicola Zakas C. - 12 Gen 2009 #
Ciao Nicola,
Recentemente ho iniziato ad esplorare yuitest per unit testing del codice JS su un portale esistente che abbiamo ereditato per il supporto e sta già usando alcune librerie YUI 2. grazie per tutti i video e blog che hai messo fuori.
1. ci sono esempi / campioni di yuitest utilizzato in scenari più pratico / realistico, come diversi contesti, ampio dom usgae esempi ecc sul sito yuitest sono molto semplicistico.
2. motivo che mi chiedo è perché il contenuto delle pagine è generalmente dinamico e si basa su alcune pre-condizioni .. l'elemento contenitore è lo stesso ma cambia il contenuto. è opportuno spegnere HTMLs diversi per ogni scenario?
3. ci potrebbe essere qualche script che utilizzano molta DOM. dovrebbe html intero come codice originale sia espulso in questi casi.
Commento di kaanta - 8 DICEMBRE 2010 #
Ciao Kaanta,
Tutti gli esempi posso condividere attualmente nella documentazione o incluso come parte del download YUI (controllare la directory test nel file ZIP).
Se si sta testando un sacco di interazione in una pagina, poi io di solito suggerisco di carico di prova YUI sulla pagina attuale e l'esecuzione del test di lì. In questo modo, non dovete preoccuparvi di spegnendo alcuni pezzi della pagina per cose di lavoro.
Commento di Nicola Zakas C. - 8 Dic 2010 #