AntonioGanci

Il blog di Antonio Ganci
posts - 201, comments - 420, trackbacks - 31

Scrivere test automatici per Javascript - parte 3

Prima di proseguire consiglio la lettura della prima parte e della seconda parte. In questo post affronteremo l'argomento dei mock object. Una prima tentazione potrebbe essere quella di cercare una libreria di mock per Javascript, ma vista la sua natura dinamica proviamo a farne a meno.

Partiamo da un esempio per introdurre l'argomento. Supponiamo di voler testare il seguente metodo:

function show_alert(text) {
    alert(text);
}

Ovviamente se eseguiamo tale metodo vedremo comparire una message box. Vediamo se riusciamo a testare l'interazione. Per prima cosa occorre che quando viene chiamato alert venga eseguita una function nostra e non quella standard. Occorre anche che quando il test termina l'esecuzione, venga ripristinata la vecchia function.

test("show alert", function() {
        var old_alert = alert;
        alert = function() {
        };
        
        show_alert('Ciao!');
        
        alert = old_alert;
    });

Se proviamo ad eseguire il metodo di test in QUnit vedremo che non viene più visualizzato l'alert. In quanto abbiamo sostituito alert con una function vuota.

Questo a noi non basta perché vogliamo testare che venga chiamato alert con un certo parametro una sola volta. Aggiungiamo quindi del comportamento al nostro mock.

test("show alert", function() {
        var old_alert = alert;
        var alert_call_count = 0;
        alert = function() {
            alert_call_count++;
        };
        
        show_alert('Ciao!');
        
        equals(alert_call_count, 1);
        
        alert = old_alert;
    });

Il test sta diventando illegibile, facciamo un primo passo portando il codice di setup nel setup del modulo. In QUnit si possono dichiarare dei moduli che assomigliano agli attributi Setup e TearDown delle Fixture di NUnit.

Ecco un esempio di dichiarazione di modulo con i metodi setup e teardown:

module("module name", {
        setup: function() {
            // setup code
        },
        teardown: function() {
            // teardown code
        }
    })

Proviamo ad applicare il concetto appena esposto al test precedente:

var old_alert;
    var alert_call_count = 0;
    module("show alert", {
        setup: function() {
            old_alert = alert;
            alert_call_count = 0;
            alert = function() {
                alert_call_count++;
            };
        },
        teardown: function() {
            alert = old_alert;
        }
    })
    
    test("show alert", function() {
        show_alert('Ciao!');
        
        equals(alert_call_count, 1);
    });

Il test si è accorciato notevolmente, ma se abbiamo mock più complicati il codice del setup diventerebbe presto molto complicato. La logica precedente comunque si puo' estrarre un oggetto Mock in modo da semplificare la scrittura dei test.

Per testare il parametro passato si puo' procedere in maniera simile basta salvarsi il valore in una variabile e poi fare la assert su quel valore.

Print | posted on venerdì 11 febbraio 2011 16:56 | Filed Under [ Tips ]

Feedback

Gravatar

# re: Scrivere test automatici per Javascript - parte 3

@Luca

I problemi che riporti mi sembrano piu che altro legati alla natura dinamica di JS piuttosto che ad uno stile di testing/mocking. Sostanzialmente bisogna dimenticarsi tutti gli strumenti strumenti a cui siamo abituati con i linguaggi statici, praticamente si puo fare affidamento solo a Ctrl-F.

> come hai notato il metodo Klass.method() é indicato negli argomenti di spyOn() con una *stringa*

In JS non c'è differenza tra usare una stringa oppure un field di un oggetto. Per esempio questi 2 comandi sono equivalenti:

a.aMethod = function () {};
a['aMethod'] = function () {};

a meno di "guess" magici e inaffidabili di alcuni IDE, sono anche grossomodo equivalenti dal punto di vista della manutenibilità.

Per entrare nell'ottica JS tieni presente che:

* Le classi non esistono, al massimo un oggetto puo essere creato "copiando" da un'altro oggetto.
* Gli oggetto sono delle Map<String, Object> (Dictionary<string, object>)
16/03/2011 21:41 | Gian Marco Gherardi
Gravatar

# re: Scrivere test automatici per Javascript - parte 3

Ho dato uno sguardo all'implementazione di jsfake, quello che fa è iterare tutti i fileds di un oggetto e sostituirli con il metodo "fake".

a parte i dubbi sul funzionamento di questa tecnica con catene di prototipi e la "opinione" del framework sul modo di identificare membri privati, la cosa in generale mi sembra sensata.

Tieni conto che con questa tecnica poni una dipendenza temporale tra il momento del mocking e il momento della definizione dei membri di una classe. In un linguaggio statico la definizione dei membri di una classe è fatta esclusivamente a cmopile time quindi non è un problema, mentre in un linguaggio dinamico i membri possono essere aggiunti in qualsiasi momento, anche dopo che ne è stata fatta la copia stub.

28/04/2011 17:26 | Gian Marco Gherardi
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET