Nello scorso post
ho descritto come scrivere test automatici per Javascript. Uno degli svantaggi della soluzione proposta
sta nel ricordarsi di chiamare le function di test. Infatti se guardiamo il codice della pagina html:
$(document).ready(function(){
sum_test();
})
Vediamo la chiamata a sum_test che contine il test. Se abbiamo molti di questi metodi la manutenzione dell'elenco puo'
diventare piuttosto noiosa e error-prone.
Una soluzione è quella di creare un oggetto Javascript che esegua automaticamente tutte le function
che terminano per _test.
In Javascript esiste l'oggetto globale window il quale contiene, tra le altre cose, tutte le function definite dall'utente.
Abbiamo quindi sfruttato questa caratteristica per realizzare un test runner di cui riporto il codice.
function TestRunner(filter) {
var test_filter = filter;
this.run = function() {
var tests = test_filter.select_all();
for (var test_index in tests) {
tests[test_index]();
}
}
}
var TestFilter = function(test_container) {
var container = test_container;
this.select_all = function(){
var properties = get_all_accessible_properties();
return select_test_functions(properties);
};
var get_all_accessible_properties = function() {
var result = [];
for (var property_name in container) {
if(is_property_accessible(property_name)) {
result.push(container[property_name]);
}
}
return result;
};
var select_test_functions = function(properties) {
var result = [];
for (var property_index in properties) {
var property = properties[property_index];
if(is_test_function(property)) {
result.push(property);
}
}
return result;
};
var is_property_accessible = function(property_name) {
try {
container[property_name];
return true;
}
catch(exc) {
return false;
}
};
var is_test_function = function(property) {
return typeof property === 'function' && property.toString().indexOf('_test()') >= 0;
}
};
Per invocare i test basta sostituire la precedente chiamata a sum_test con:
new TestRunner(new TestFilter(window)).run();
Una cosa interessante del codice precedente è che mostra una tecnica (non l'unica possibile) per definire gli oggetti in Javascript.
Prendiamo ad esempio il TestRunner. Il codice:
function TestRunner(filter) {
}
Definisce un oggetto chiamato TestRunner con un costruttore con un parametro.
Il quale si puo' instanziare con una sintassi molto simile al C#
new TestFilter(someParameter)
All'interno dell'oggetto si possono definire dei field privati. Nel nostro caso aggiungiamo il field test_filter inizializzato con il valore
passato dal costruttore:
function TestRunner(filter) {
var test_filter = filter;
}
A questo punto possiamo aggiungere un metodo pubblico:
function TestRunner(filter) {
var test_filter = filter;
this.run = function() {
// do something
}
}
}
Per i metodi privati la tecnica è analoga con l'unica differenza di mettere var al posto di this. come si vede per
l'oggetto TestFilter.
Rimane un ultimo problema da risolvere. Se un test di QUnit solleva un'eccezione non vedo la barra rossa.
Per evitare questa mancanza possiamo modificare il codice precedente con questo:
<script type="text/javascript">
$(document).ready(function() {
try {
new TestRunner(new TestFilter(window)).run();
}
catch (e) {
module("Fatal errors");
test("Exception thrown by running tests", function() {
ok(false, 'Message: ' + e.message + ' -- StackTrace: ' + e.stack);
});
}
});
A questo punto siamo pronti per scrivere i nostri test e vederli eseguiti all'interno del browser.
Buona barra verde!