Mondi su mondi, sistemi di sistemi.

Test della GUI: un esempio con l’autocomplete di YUI

Qual è il problema?

Una delle cose abbastanza incasinate da testare sono gli elementi dell’elementi AJAX, come l’AutoComplete. Non sono mai riuscito a testare l’evento che corrisponde direttamente allo use case, ovvero, l’utente seleziona un’elemento della lista e nel campo associato viene inserito un valore, perlomeno con YUI. Ho provato anche con Selenium ma senza successo. Forse impegnandosi di più si potrebbe ottenere qualcosa di meglio ma, visti i risultati (vedi discus­sione in fondo), non so se sia necessario.

Riduciamo i danni

In mancanza dell’ideale pos­siamo comunque ridurre di molto la porzione di codice non testata. In primo luogo pos­siamo testare in modo estensivo la data source associata all’AutoComplete. In secondo luogo pos­siamo usare i custom events per isolare e testare il codice che si occupa delle conseguenze della selezione.

Lo scenario da testare

Facciamo un esempio clas­sico: un AutoComplete che, alla selezione del nome del cliente, imposta anche il valore della primary key di quel record in un campo nascosto.

Usiamo i custom events

Se non tenes­simo conto delle esigenze dei test, la soluzione sarebbe semplice:

clienteAC.itemSelectEvent.subscribe(
    function(sType, args) {
        clienteAC.getInputEl().value = args[2].nome;
        document.form-cliente.id_cliente.value = args[2].id;
    }
);

Invece, con gli eventi custom pos­siamo scrivere questo:

clienteAC.itemSelectEvent.subscribe(
    function(sType, args) {
        customItemSelectEvent.fire({
            selectedItem: args[2]
        });
    }
);

Ovvero, alla selezione dell’utente, lanciamo un evento che contiene la selezione stessa.

Dall’altra parte, il listener raccoglie l’evento, esegue le operazioni neces­sarie e al termine lancia un secondo evento, comunicando la fine dell’operazione:

// aggiorniamo il campo associato all’auto complete
clienteAC.getInputEl().value = args[2].nome;
// impostamo il valore della primary key
document.form-cliente.id_cliente.value = args[2].id;
// “avvisiamo” che abbiamo finito
customLoadCompleteEvent.fire("Finished");

Testiamo!

Questo secondo evento è essenziale per i test, infatti, a questo punto pos­siamo semplicemente inviare un customItemSelectEvent e aspettare l’altro evento in risposta:

//…
name: "Test auto complete cliente",
testSelectEvent: function() {
    var resume = function (ev, type) {
        this.resume(function() {
            customLoadComplete.unsubscribe(resume);
            YAHOO.util.Assert.areEqual(
                 "Mario Rossi",
                 document.form-cliente.nome.value,
                 "Il nome del cliente dovrebbe essere 'Mario Rossi'"
             );
        });
    };
    customLoadComplete.subscribe(resume, this, true);
    customItemSelect.fire({
        selectedItem:{
            id: 1,
	    nome: "Mario Rossi"
	}
    });
    this.wait();
},

Un bilancio

Un dubbio legittimo che può venire è se valga la pena di complicare così il codice solo per poterlo testare. È un dubbio che ho spesso!

In generale, l’effetto delle modifiche in funzione della “testabilità” è positivo. L’importante è non spingersi al punto di creare metodi o variabili che vengono usate solo nei test: a mio parere è un errore.

In questo caso credo che il codice risultante sia più pulito e meglio separato. Adesso pos­siamo sfruttare l’evento finale customLoadComplete in coda alla selezione dell’utente per aggiornare altri elementi della pagina, senza che ci sia una dipendenza diretta con l’AutoComplete.

All’inizio accennavo al fatto che, nonostante tutto, sia forse pos­sibile testare direttamente l’AutoComplete. Tuttavia ho l’impressione che avrei ottenuto una qualità inferiore, con più rigidità. A questo punto lo prenderei in considerazione solo come test complementare, utile ma non indispensabile.

Per proseguire

Commenti e trackback sono disabilitati.