Sobald man sich im Internet befindet, wird man merken das die Testfälle etwas anders “gestrickt” werden müssen, zbsp. wenn man auf die Antwort warten muss.
Das Testen von Asynchrone Funktionen möchte ich gerne in diesem Tutorial beschreiben.
Mocken von Ajax Request für Testzwecke
Durch die Same Origin Regel ist es nicht möglich vom lokalen Computer, Scripte aus dem Internet zu benutzen, jedoch möchten wir gerne unsere Methoden Testen, dafür gibt es die Möglichkeit Funktionen zu Mocken d.h. zu simulieren.
Für diesen Testfall benutze ich Mockjax welches einfach zu implementieren und noch einfacher zu benutzen ist.
Jasmine Testprojekt
Als Projekt verwende ich das Testprojekt aus dem Tutorial
Jasmine JavaScript Test, “toBe || not.toBe” wieder.
Aufbau eines Mock Objektes
Ein einfaches Mock Objekt von Mockjax ist wie folgt aufgebaut:
Attribut | Erläuterung | Werte |
url | Die Adresse welche simuliert werden soll, diese muss auf eine reale Datei/ Adresse zeigen. | login.php |
dataType | Der Datentyp des Rückgabewertes bei Text kann dieses Attribut weggelassen werden | ‘json’, ‘html’, ‘xml’ |
responseTime | Antwortzeit in Millisekunden | 1000 |
responseText | Antwort des MockObjektes | ‘Hello World’ {say: ‘Hello World!’} |
Es gibt noch weitere Attribute welche auf der GitHub Seite vom Mockjax Plugin beschrieben werden.
Einbinden von Mockjax
Für das Mocken wir “nur” die JavaScript Datei “jquery.mockjax.min.js” mit
<script src="../js/jquery.mockjax.min.js"></script>
in die Datei “SpecRunner.html” eingebunden. Es ist darauf zu achten das dieses nach dem Einbinden von jQuery geschieht.
Einen Callback simulieren
Um einen einfachen Callback zu simulieren, kann man folgenden Code verwenden.
$.mockjax({ url: "login.php", responseTime: 1000, responseText: 'Test Result' });
Wenn man nun ein Ajax Request auf die Adresse “login.php” erstellt wird unser Mockobjekt ausgeführt.
var callAsyncFuntionExtern = function(){ $.mockjax({ url: "hello.php", responseTime: 1000, responseText: 'Hello World!' }); $.ajax({ url: "hello.php", async: true }).done(function (response) { console.log(response); $.mockjaxClear(); }); }
Wenn man diese Funktion aus einer HTML Seite aufruft, dann erhält man folgende Ausgabe auf der Konsole.
Als ersten Eintrag sieht man das gemockte Objekt mit seinen Attributen und nach kurzer Zeit (1sek.) erscheint der Wert “Hello World!”.
Besonderheit beim Attribut URL
Das Attribut ‘URL’ sollte unique d.h. einzigartig sein, denn wenn man 2x das gleiche Mockobjekt jedoch mit unterschiedlichen Datentypen oder Rückgabe werte erstellt so wird immer das erste erstellte Objekt gefunden und benutzt.
Hier ein Beispiel:
var callFuntion1Extern = function(){ $.mockjax({ url: 'greeting.php', dataType: 'text', responseTime: 1000, responseText: 'Hello World!' }); } var callFuntion2Extern = function(){ $.mockjax({ url: 'greeting.php', dataType: 'json', responseTime: 1000, responseText: { say: 'json -> Hello World!' } }); } function SimpleMockSample(){ this.callFuntion1 = callFuntion1Extern; this.callFuntion2 = callFuntion2Extern; } var simpleMockSample = new SimpleMockSample(); simpleMockSample.callFuntion1(); simpleMockSample.callFuntion2(); $.ajax({ url: 'greeting.php', dataType: 'json', async: true }).done(function (json) { console.log(json.say); }).fail(function (json) { console.log("Fehler!"); });
Durch dieses Beispiel wird deutlich warum das URL-Attribut unique sein muss, denn woher soll der Ajax aufruf wissen welches Objekt jetzt aufgerufen werden soll?
Mögliche Rückgabewerte eines Mockobjektes
Es ist nicht nur möglich einfache Werte wie “Hello World!” zurückzugeben sondern auch komplexe Objekte wie ein JSON, HTML oder XML Objekt.
Für das Mocken von XML Objekten wird ein das XML DOM Plugin benötigt.
Datentyp Text
Der einfachste Datentyp ist Text.
$.mockjax({ url: 'greeting.php', dataType: 'text', responseTime: 1000, responseText: 'Hello World!' });
Datentyp JSON
Ein JSON Objekt, ist ein Objekt mit Key Value paaren. Ein Mockobjekt mit einem Rückgabewert für ein JSON Objekt könnte etwa so aussehen:
$.mockjax({ url: 'greeting.php', dataType: 'json', responseTime: 1000, responseText: { say: 'json -> Hello World!'} });
Datentyp HTML
Der Datentyp HTML kann eine komplexte oder einfache HTML Struktur zurückliefern.
$.mockjax({ url: "greeting.php", dataType: "html", responseText: "<div>Hello World!</div>" });
Datentyp XML
Ähnlich wie beim HTML kann auch XML eine Struktur zurückliefern jedoch wird für diesen Datentyp ein extra Plugin benötigt.
$.mockjax({ url: "greeting.php", dataType: "xml", responseXML: "<document><say>Hello World!</say></document>" });
Erstellen eines asyncronen Testfalls mit Jasmine
Da wir jetzt mit Mockjax uns Objekte mocken (simulieren) können, wollen wir nun ein asyncronen Testfall erstellen.
describe("async test", function () { var simpleAsyncObject; beforeEach(function (done) { loadFixtures('ajaxfixture.html'); $.mockjax({ url : 'login.php', responseTime : 1000, responseText : 'Hello World!' }); var simpleAsyncObject = new SimpleAsyncObject(); simpleAsyncObject.callAsyncFunction($('#output')); setTimeout(function () { done(); }, 2000); }); it("test async call", function () { var outputText = $('#output').text(); expect(outputText).not.toBe(''); }); });
Zuallererst müssen wir mit der Funktion “beforeEach” unsere asyncrone Funktion aufrufen. Nachdem aufrufen der Funktion wird ein Timeout (“setTimeout”) gesetzt, in diesem Beispiel sind es 2 Sekunden. Ist der Timeout erfolgt, so wird die Funktion “done();” aufgerufen, somit ist der Timeout erfolgreich abgehandelt und es wird der eigentliche Testfall aufgerufen in welchem wir auf das erwartete Ergebnis prüfen.