Test your project

JavaScript client- und serverseitig testen
Kommentare

Kennen Sie das ungute Gefühl, wenn Sie ein neues Feature umsetzen und nicht genau wissen, ob es in seiner gesamten Funktionalität so arbeitet, wie es soll? Noch schlimmer ist es, wenn Sie bestehende Funktionalität anpassen und nicht wissen, ob nach der Änderung noch alles so funktioniert wie zuvor. Für Ihr Problem existiert allerdings eine sehr einfache Lösung: Testen Sie Ihr Projekt. Auf Serverseite hat sich das Testen von Methoden bereits seit vielen Jahren bewährt und schafft Sicherheit für die Entwickler. Anders sieht es im Frontend aus. Was und vor allem wie soll man JavaScript testen? Dabei existieren auch für JavaScript zahlreiche Frameworks, die Ihnen die Möglichkeit bieten, Ihre Applikation abzusichern.

Wie in anderen Sprachen existieren auch für JavaScript Implementierungen von Testframeworks. Und hier liegt auch schon das Problem: Wo es in anderen Sprachen nur wenige Frameworks gibt oder sich ein oder wenige Frameworks als Standard etabliert haben, existieren in JavaScript zahlreiche Frameworks nebeneinander. Und fast jedes JavaScript-Framework bringt sein eigenes Testframework mit. Setzen Sie ein Framework wie beispielsweise jQuery ein, stehen Sie in diesem Fall vor einer relativ einfachen Auswahl: Entweder Sie entscheiden sich für den Weg des geringsten Widerstands und setzen das zugehörige Testframework, in diesem Fall QUnit, ein oder Sie verwenden ein plattformunabhängiges Framework. Wie aber treffen Sie die richtige Entscheidung?

Dieser Artikel soll Ihnen dabei helfen, das beste Framework für Ihre Situation auswählen zu können. Außerdem werden einige Kriterien vorgestellt, anhand derer Sie auch andere Testframeworks, die hier nicht behandelt werden, beurteilen und bewerten können.

Aus der Fülle an verfügbaren Frameworks greifen wir hier vier heraus, die die verschiedenen Bereiche recht gut widerspiegeln. Dabei reicht die Auswahl von recht einfachen Umsetzungen, die Sie für reine Assertion-Tests verwenden können bis hin zu umfangreichen Implementierungen, die es Ihnen ermöglichen, mehrere Browser zu kontrollieren und das Testen von asynchronen Funktionen erlauben. Zunächst sehen wir uns die Kandidaten im Vergleich an. Die Kriterien sind hier:

  • die Installation des Frameworks
  • wie die Tests organisiert werden können
  • welche Assertions Ihnen zur Verfügung stehen

JsUnit

Beginnen wir mit dem sehr alten, aber dennoch einfachen Framework JsUnit. Die Entwicklung an diesem Werkzeug begann bereits im Jahr 2001. Die letzte Version 1.3 wurde 2007 veröffentlicht. Seither wird JsUnit nicht mehr aktiv weiterentwickelt. Mit diesem Framework unternahmen die Entwickler den Versuch, das Testframework JUnit von Java in JavaScript zu portieren. JsUnit ist eine Open-Source-Software, die unter der Apache-Lizenz verfügbar ist. Heruntergeladen werden kann JsUnit von der Webseite [1].

Die Installation und Verwendung dieses Frameworks gestalten sich problemlos. Sie können es an einer beliebigen Stelle im Dateisystem installieren, an der Sie mit Ihrem Browser Zugriff haben. Dazu müssen Sie lediglich ein gezipptes Tar-Archiv von Sourceforge herunterladen und es entpacken. Im Paket befinden sich im Verzeichnis „jsunit“ und dessen Unterverzeichnis „lib“ die Dateien JsUnit.js und JsUtil.js. Diese beiden Dateien benötigen Sie zur Ausführung der Tests. Außerdem müssen Sie eine AllTests.html erstellen, die als Startpunkt für die Tests dient. Hier können Sie dann sowohl Ihre Quellcodedateien, die Sie testen möchten, als auch die Dateien mit den Tests mittels -Tag einbinden und müssen dann lediglich diese Datei in Ihrem Browser laden, und die Tests werden ausgeführt. Den Aufbau der AllTests-Datei können Sie aus dem Verzeichnis jsunit/samples aus der Datei AllTests.html kopieren. Sie müssen nur ein paar Stellen für Ihre Zwecke anpassen und haben dann bereits eine voll funktionsfähige Testumgebung.

Ein Unit Test in JsUnit besteht aus einer Methode, die eine oder mehrere so genannte Assertions enthält. Die Methoden beginnen jeweils mit dem Präfix test, dem ein möglichst beschreibender Name für den Test folgt. Das Präfix ist zwingend, da eine Methode ohne es nicht als Test erkannt und daher nicht ausgeführt wird. Die Tests sind Teil einer Klasse, die von der JsUnit-Klasse TestCase über Prototypenvererbung ableitet. Die einzelnen Testklassen werden dann weiter in so genannten Testsuites gruppiert. Eine Testsuite-Klasse wird von der JsUnit-internen Klasse TestSuite abgeleitet. Führen Sie die Tests in Ihrem Browser aus, wird diese logische Gruppierung durch die Ausgabe von > Starting test suite… und < Completed test suite… verdeutlicht.

Innerhalb dieser Ausgaben wird für jeden ausgeführten Test die Nummer des Tests, die Klasse und der Methodenname angezeigt. Falls Sie die Methoden setUp und tearDown in einer Testklasse definieren, werden sie vor beziehungsweise nach jedem Test ausgeführt. So können Sie die Umgebung für die Tests vorbereiten beziehungsweise die Auswirkungen der Tests zurücksetzen.

Zum Formulieren der Tests stehen Ihnen eine Reihe von Assertions zur Verfügung. Dabei handelt es sich um Methoden, mit deren Hilfe Sie einen bestimmten Sachverhalt prüfen können.

Tests sind normalerweise durch die drei A gekennzeichnet: Arrange, Act und Assert.

Das bedeutet, dass Sie zuerst eine Umgebung schaffen, in der ein bestimmter Test ablaufen soll, danach findet die zu testende Aktion statt und im dritten Punkt, dem Assert, kommen die Assertion-Methoden des Frameworks ins Spiel. Sie dienen dazu, das Ergebnis der Aktion mit einer bestimmten Erwartung abzugleichen. Einige Beispiele für Assertions finden Sie in Tabelle 1.

Assertion

Funktion

assertEquals

Vergleich zwischen Ergebnis und Erwartung, nicht typsicher

assertSame

Vergleich zwischen Ergebnis und Erwartung, typsicher

assertMatches

Prüfung, ob ein regulärer Ausdruck einer Zeichenkette entspricht

assertNull

Prüfung, ob der Wert Null ist

assertUndefined

Prüfung, ob der Wert Undefined ist

assertTrue

Prüfung, ob der Wert True ist

assertFalse

Prüfung, ob der Wert False ist

Tabelle 1: Assertions in JsUnit

Für einige Assertions wie beispielsweise assertSame, assertNull oder assertUndefined existieren auch entsprechende Negierungen, also zum Beispiel assertNotSame, was die Bedeutung der Assertion ins Gegenteil umkehrt, sodass Sie nicht erst umständlich Ihren Ausdruck umkehren müssen und der Test dadurch unleserlich wird. Listing 1 zeigt einen Unit Test mit JsUnit, Abbildung 1 zeigt die Ausgabe.

function MyTest(name) {
    TestCase.call(this, name);
}
MyTest.prototype = new TestCase();
MyTest.prototype.testAdd = function() {
    this.assertEquals(1 + 1 , '2');
}

function MyTestSuite() {
    TestSuite.call(this, "MyTestSuite");
    this.addTestSuite(MyTest);
}
MyTestSuite.prototype = new TestSuite();
MyTestSuite.prototype.suite = function() {
    return new MyTestSuite();
}

Abb. 1: Ausgabe von Unit Tests unter JsUnit

Zugegebenermaßen ist JsUnit mittlerweile in die Jahre gekommen und es gibt modernere und vor allem angenehmer zu bedienende Testframeworks. Nichtsdestotrotz finden sich die in diesem Abschnitt beschriebenen Grundlagen in ähnlicher Art und Weise auch in den übrigen Frameworks wieder.

QUnit

Ein weiteres Framework aus der xUnit-Familie ist QUnit. Es wird von den Projekten jQuery, jQuery UI und jQuery Mobile verwendet, um die Bibliotheken selbst zu testen. Aus diesem Grund kann es bedenkenlos eingesetzt werden, falls Ihre Applikation auf einer dieser Bibliotheken basiert. Ursprünglich wurde QUnit im Zuge von der jQuery-Bibliothek entwickelt und gehört somit zu den Testframeworks, die sehr eng mit einem bestimmten Framework beziehungsweise einer Bibliothek verbunden sind. 2008 wurde QUnit aus dem jQuery-Projekt ausgegliedert und steht seither auch als unabhängiges Testframework abseits von jQuery zur Verfügung. Das bedeutet für Sie als Entwickler, dass Sie kein jQuery in Ihrer Applikation einsetzen müssen, um QUnit als Testframework einzusetzen. QUnit setzt außerdem die CommonJS-Spezifikation für Unit Tests in JavaScript um und war auch an deren Erstellung beteiligt. Ziel dieser Spezifikation ist es, JavaScript besser zu standardisieren.

QUnit ist als Open-Source-Software auf [2] zum Download verfügbar und wird auf [3] unter der MIT-Lizenz entwickelt.

QUnit kann wie JsUnit auch direkt aus dem Browser ausgeführt werden. Es ist keine Serverkomponente notwendig, um die Tests auszuführen. Die Installation gestaltet sich ähnlich wie bei JsUnit, jedoch sind noch weniger Schritte notwendig, und die grafische Ausgabe ist wesentlich ansprechender. Um QUnit zu betreiben, benötigen Sie lediglich eine HTML-Seite, die das QUnit-Style-Sheet und den Quellcode einbindet. Außerdem benötigt QUnit zur Darstellung der Ergebnisse einen Div-Container mit der ID qunit. Sind diese Voraussetzungen erfüllt, können Sie Ihre Quell- und Testdateien einbinden und die Tests ausführen. Ein konkretes Beispiel für den Aufbau eines QUnit-Set-ups finden Sie auf der Webseite von QUnit.

QUnit bietet zur Erstellung von Tests eine Reihe von Assertions, die Sie verwenden können, um zu prüfen, ob die verschiedenen Funktionen Ihrer Applikation arbeiten wie erwartet. Ein Test kann wiederum eine oder mehrere Assertions aufweisen. Ein Test selbst besteht aus einem Aufruf der test-Funktion. Diese erwartet zwei Parameter: Der erste Parameter besteht aus einer kurzen Beschreibung des Tests, die später in der Übersicht der Ergebnisse zu sehen ist. Der zweite Parameter besteht aus einer Callback-Funktion mit der eigentlichen Testlogik. Bei der Umsetzung wird wie gewohnt nach dem Schema Arrange, Act und Assert vorgegangen, wobei Sie beachten sollten, dass Sie maximal ein bis drei Assertions pro Test einsetzen, da mehr Assertions ein sicheres Zeichen dafür sind, dass ein Test zu viele Sachverhalte abdeckt. Die einzelnen Tests lassen sich wiederum in so genannte Module gruppieren, die bei der späteren grafischen Darstellung der Abgrenzung der einzelnen Gruppen dienen. Ein Modul wird durch den Aufruf der module-Funktion eingeleitet. Der einzige Parameter dieser Funktion besteht aus einer Zeichenkette, die das Modul beschreibt. Der optionale zweite Parameter des module-Aufrufs besteht aus einem Objekt mit den Schlüsseln setup und teardown, deren Wert jeweils eine Funktion ist, die vor beziehungsweise nach jedem Test dieses Moduls aufgerufen werden. Die setup-Funktion dient wie schon in JsUnit dazu, die Umgebung für die Tests vorzubereiten und teardown sorgt entsprechend dafür, nach dem Test eine saubere Umgebung zu hinterlassen. Tabelle 2 zeigt eine Übersicht der Assertions in QUnit.

Assertion

Funktion

equal

Vergleich zwischen Wert und Erwartung, nicht typsicher

deepEqual

Rekursiver Vergleich zwischen Wert und Erwartung

strictEqual

Typsicherer Vergleich zwischen Wert und Erwartung

ok

Prüfung, ob der übergebene Wert wahr ist

throws

Prüfung, ob eine Exception geworfen wird

Tabelle 2: Assertions in QUnit

Für die Assertions equal, deepEqual und strictEqual existiert jeweils eine Negierung, wobei dem Namen lediglich ein not vorangestellt wird, also beispielsweise notEqual. Folgend ein Unit Test mit QUnit, Abbildung 2 zeigt die Ausgabe:

module('MyTest');  test('Test Addition', function () {     equal(1 + 1, 2, 'one and one should be two'); });

Abb. 2: Ausgabe von Unit Tests unter QUnit

In QUnit können Sie jedoch nicht nur einzelne Tests in Testsuites gruppieren und mit den verfügbaren Assertions prüfen, ob bestimmte Werte Ihren Erwartungen entsprechen. Neben diesen Features stellt Ihnen QUnit noch einige weitere Funktionen zur Verfügung. Mit der Funktion stop können Sie beispielsweise innerhalb eines Tests die Ausführung des TestRunners anhalten, um auf die Ausführung einer asynchronen Operation zu warten. Durch einen Aufruf der start-Funktion setzen Sie den TestRunner wieder fort. Außerdem können Sie Callback-Funktionen bei bestimmten Ereignissen innerhalb des Ablaufs der Tests registrieren. So können Sie beispielsweise mit QUnit.testStart einen Callback registrieren, der ausgeführt wird, sobald ein Test startet. Ähnliches existiert für die Beendigung eines Tests, für Beginn und Ende eines Moduls und der gesamten Testsuite.

QUnit ist ein modernes, leichtgewichtiges Testframework, mit dem Sie eine Vielzahl von Applikationen testen können. Die Entwickler von QUnit haben sich durch die Prinzipien der verschiedenen xUnit-Frameworks inspirieren lassen und damit ein solides Werkzeug zur Qualitätssicherung geschaffen.

Jasmine

Mit Jasmine verlassen wir nun die xUnit-Frameworks und widmen uns einer anderen Art der Softwaretests. Jasmine ist ein Framework für Behavior-driven Development, das den Ansatz verfolgt, die Tests verständlicher zu formulieren. Jasmine kann mit seiner einfachen und gut verständlichen Syntax jedoch auch für klassisches Unit Testing von JavaScript-Applikation verwendet werden. Es zählt zu den unabhängigen Frameworks, das bedeutet, dass weder ein zusätzliches JavaScript-Framework noch eine weitere Bibliothek benötigt wird. Wie auch schon die beiden anderen Frameworks, die wir uns bereits angesehen haben, können auch die Jasmine-Tests direkt aus dem Browser heraus ausgeführt werden.

Jasmine ist wie die anderen Testframeworks auch eine Open-Source-Software und wird auf GitHub entwickelt. Der Quellcode ist unter der MIT-Lizenz verfügbar. Die Webseite des Projekts finden Sie unter [4].

Die Installation verläuft ähnlich wie schon bei JsUnit und QUnit: Laden Sie das Standalone-Release herunter und entpacken es, haben Sie bereits eine voll funktionsfähige Installation von Jasmine. Der Einstiegspunkt besteht aus der Datei SpecRunner.html. Öffnen Sie diese in Ihrem Browser, werden die vordefinierten Tests ausgeführt. Sie können im nächsten Schritt sowohl die Tests als auch den Quellcode durch Ihre eigene Applikation und die entsprechenden Tests ersetzen und können Jasmine verwenden. In der SpecRunner.html-Datei wird das Jasmine-Style-Sheet eingebunden, außerdem der Quellcode von Jasmine selbst und eine Datei, die dafür sorgt, dass die Ausgabe im HTML-Format erfolgt. Für die Ausführung der Tests selbst sorgt ein Codeblock, der ebenfalls Bestandteil der mitgelieferten SpecRunner-Datei ist.

Bei der Formulierung von Tests mit Jasmine können Sie ebenfalls auf eine Reihe von Assertions zurückgreifen. In Jasmine werden sie als Matcher bezeichnet. Ein Test beginnt nach dem Aufbau der Umgebung und der Durchführung der Aktion stets mit dem Aufruf der expect-Funktion. Diese erhält den Wert, der geprüft werden soll, als Parameter. Auf dem Rückgabewert der expect-Funktion können Sie dann den Matcher aufrufen. Der Test selbst wird durch einen Aufruf der it-Funktion von Jasmine definiert. Dieser Funktion werden zwei Parameter mitgegeben. Der erste ist die Beschreibung des Tests und der zweite ist eine Callback-Funktion, die den Test enthält. Die Tests werden in Testsuites gruppiert. Der erste Parameter, die Beschreibung, wird nach dem Durchlauf der Tests mit den Ergebnissen angezeigt, damit der Test bei einem eventuellen Fehlschlag zugeordnet werden kann. Eine Testsuite kann dabei einen oder mehrere Tests beinhalten. Eine Testsuite wird durch einen Aufruf der describe-Funktion erstellt. Die Zeichenkette, die als Erstes an die Funktion übergeben wird, beschreibt die Gruppe der Tests, die in der Testsuite enthalten sind. Als Zweites wird ein Callback übergeben, der die einzelnen Aufrufe der it-Funktion enthält. Analog zu den setup- und teardown-Funktionen von JsUnit und QUnit existieren in Jasmine die Funktionen beforeEach und afterEach. Sie werden aufgerufen, um die Umgebung für die Tests bereitzustellen oder nach den Tests aufzuräumen. Beiden Funktionsaufrufen werden Funktionen übergeben, die vor beziehungsweise nach jedem Test ausgeführt werden.

Mit Tabelle 3 erhalten Sie einen Überblick über einen Teil der verfügbaren Matcher von JavaScript. Die Matcher können negiert werden, indem zwischen dem Aufruf von expect und dem eigentlichen Matcher ein .not gestellt wird, also expect(x).not.toBe(y). Mit Jasmine haben Sie die Möglichkeit, die Palette der existierenden Matcher um Ihre eigenen Matcher zu erweitern. Das bietet sich vor allem an, wenn Sie in Ihren Tests häufig spezielle Sachverhalte prüfen müssen, für die entweder eine Helper-Funktion definiert werden muss oder die nur sehr aufwändig geprüft werden können.

Matcher

Funktion

expect(x).toBe(y)

Vergleicht x mit y, typsicher

expect(x).toEqual(y)

Vergleicht x mit y, typsicher, kann mit verschiedenen Strukturen umgehen

expect(x).toMatch(y)

Vergleicht x mit dem regulären Ausdruck y

expect(x).toBeDefined()

Prüfung, ob x definiert ist

expect(x).toBeNull()

Prüfung, ob x Null ist

Tabelle 3: Assertions in Jasmine

Ein Unit Test mit Jasmine sieht wie folgend aus, Abbildung 3 zeigt die Ausgabe:

describe("MyTest", function () {     it("should add two numbers", function () {         expect(1 + 1).toEqual(2);     }); });

Abb. 3: Ausgabe von Unit Tests unter Jasmine

Wie auch schon bei QUnit geht der Funktionsumfang von Jasmine weit über die reinen Assertions hinaus. Ihnen als Entwickler stehen mit den so genannten „Spies“ Wrapper-Funktionen zur Verfügung, mit denen Sie die Verwendung bestimmter Funktionen innerhalb Ihres Tests überwachen und wiederum Assertions auf die Spies durchführen können. Spies dienen jedoch nicht nur der Überwachung, sondern können auch dazu verwendet werden, das Verhalten einer Funktion aktiv zu verändern. So können Sie mit der andReturn-Methode eines Spy-Objekts bestimmen, welchen Wert ein Aufruf auf die Funktion zurückgeben soll, über der der Spy liegt.

Mit der Methode jasmine.Clock.useMock erhalten Sie außerdem die Kontrolle über die Zeit innerhalb Ihrer Tests. Mit dem Aufruf dieser Methode vergeht innerhalb Ihres Tests keine Zeit, wenn Sie die Funktionen setTimeout und setInterval verwenden. Sie können jasmine.Clock.tick verwenden, um die Uhr in Ihren Tests weiterzudrehen. Zu diesem Zweck geben Sie der Methode die Anzahl an Millisekunden mit, die ablaufen sollen.

Mit einer Kombination der Funktionen run und waitFor erhalten Sie die Möglichkeit, innerhalb Ihrer Tests auch asynchrone Funktionen zu testen. Dabei kapseln Sie die zu testende Funktion in einer Callback-Funktion, die an die run-Funktion übergeben wird. Darauf folgt ein Aufruf von waitFor. Dieser erhält ebenfalls eine Callback-Funktion, eine Zeichenkette und einen Time-out-Wert. Die Callback-Funktion wird so oft ausgeführt, bis sie den Wert true zurückgibt oder das Time-out abgelaufen ist. Ist das Time-out erreicht, wird die Zeichenkette als Fehlermeldung ausgegeben.

Durch die gut lesbare Syntax und die umfangreichen Funktionalitäten hat sich Jasmine in letzter Zeit zu einem der beliebtesten Testframeworks im JavaScript-Umfeld entwickelt und wird häufig in Projekten eingesetzt.

JsTestDriver

Das letzte Framework, das wir im Rahmen dieses Artikels betrachten wollen, ist JsTestDriver. Dieses Framework verfolgt einen grundlegend anderen Ansatz als die Frameworks, die wir bisher gesehen haben. Im Gegensatz zu QUnit und Jasmine, die komplett in JavaScript implementiert sind, wird JsTestDriver in Java entwickelt und daher auch komplett unabhängig von bestehenden JavaScript-Frameworks. Bisher wurden alle Unit Tests im Browser ausgeführt, beim JsTestDriver ist der Prozess hingegen etwas komplizierter. Daraus entstehen für Sie als Entwickler von Unit Tests viele Möglichkeiten, die Ihnen beispielsweise browserübergreifende Tests oder Automatisierung von Tests erlauben. Dazu aber im Verlauf der nächsten Abschnitte mehr.

Das Projekt JsTestDriver wird im Rahmen von code.google.com verwaltet und steht unter [5] in verschiedenen Varianten zum Download bereit. Zum Einstieg sollten Sie die Self-contained executable jar-Datei wählen, da Sie sich in diesem Fall nicht um die Auflösung bestehender Abhängigkeiten kümmern müssen. JsTestDriver ist wie alle bisher vorgestellten Testframeworks ein Open-Source-Projekt und unter der Apache-Lizenz 2.0 verfügbar.

Das grundsätzliche Layout einer Applikation, die mit JsTestDriver getestet werden soll, besteht aus einem Verzeichnis, in dem der Quellcode der Applikation liegt, einem weiteren Verzeichnis, in dem die Dateien liegen, die die Tests enthalten, und einer Konfigurationsdatei, die im YAML-Format verfasst wird.

Ausgeführt werden die Tests von der Kommandozeile des Systems aus. Zu diesem Zweck wird die Konfigurationsdatei vom JsTestDriver eingelesen. Diese gibt an, wo die Tests und auch der Quellcode zu finden sind. Außerdem wird der URL angegeben, über den der JsTestDriver-Server zu erreichen ist. Mit einer vollständigen Konfigurationsdatei können Sie die Serverkomponente mit dem Kommando java -jar JsTestDriver.jar –port 9876 starten. Sobald der Server läuft, können Sie einen Browser starten und sich mit dem Server verbinden. Über den URL http://localhost:9876/capture können Sie den Browser direkt mit dem Server verbinden. Anschließend können Sie die Tests über das Kommando java -jar JsTestDriver-1.3.5.jar –tests all im Verzeichnis, in dem die Konfigurationsdatei liegt, ausführen. Der entscheidende Vorteil dieses Testframeworks besteht darin, dass Sie mit einem Kommando sämtliche mit dem Server verbundene Browser ansprechen und steuern können. Im Gegensatz zu den bisherigen Testframeworks ist es so möglich, die Tests nicht nur in einem Browser auszuführen, sondern in beliebig vielen verschiedenen Browsern parallel.

Der Aufbau der einzelnen Testdateien ist relativ einfach. Jeder Test beginnt mit einem Funktionsaufruf der TestCase-Methode. Diese erhält eine Zeichenkette, die den Namen der Testsuite darstellt. Der Rückgabewert besteht aus einem Objekt, in dessen Prototypen die einzelnen Testmethoden eingehängt werden können. Die Namen der Testmethoden beginnen stets mit dem Präfix test, also beispielsweise testMyTestFunc. Wie bereits aus den übrigen Testframeworks bekannt, stehen Ihnen auch hier die Methoden setUp und tearDown zur Verfügung, über die Sie die Umgebung vor jedem Test vorbereiten beziehungsweise nach jedem Test die Umgebung wieder bereinigen können. Innerhalb der Tests können Sie auf eine Reihe von Assertions zurückgreifen, mit denen Sie die zu prüfenden Sachverhalte testen können. Wie Sie in Tabelle 4 sehen können, stehen Ihnen auch bei Tests mit JsTestDriver ähnliche Assertions zur Verfügung, wie Sie sie bereits aus QUnit und Jasmine kennen.

Assertion

Funktion

assertTrue(msg, value)

Prüfung, ob “value” wahr ist

assertFalse(msg, value)

Prüfung, ob “value” falsch ist

assertEquals(msg, expected, actual)

Prüfung, ob “expected” und “actual” die gleichen Werte besitzen

assertSame(msg, expected, actual)

Prüfung, ob “expected” und “actual” eine Referenz auf das gleiche Objekt sind

assertNull(msg, value)

Prüfung, ob “value” den Wert “null” besitzt

assertUndefined(msg, value)

Prüfung, ob “value” den Wert “undefined” besitzt

Tabelle 4: Assertions in JsTestDriver

Folgend der Unit Test mit JsTestDriver, Abbildung 4 zeigt die Ausgabe:

MyTest = TestCase("JsTestDriverTest");  MyTest.prototype.testJsTestDriver = function() {     var myFunc = function () {         return 1 + 1;     };      assertEquals(2, myFunc()); };

Abb. 4: Ausgabe von Unit Tests unter JsTestDriver

Zusätzlich zur TestCase-Funktion, mit der Sie Ihre Tests erstellen können, existiert mit AsyncTestCase eine weitere Funktion, mit der Sie Asynchronität innerhalb Ihrer Applikation testen können. Die einzelnen Test-Methoden erhalten zu diesem Zweck ein Queue-Objekt als Argument, dem Sie über die call-Methode Funktionen hinzufügen können, die sequenziell abgearbeitet werden, bis eine Assertion innerhalb der Callback-Funktionen fehlschlägt.

Durch seinen Ansatz, die Tests nicht direkt im Browser auszuführen, sondern über eine Serverkomponente, die in Java verfasst ist und die Ausführung im Browser vom eigentlichen Testablauf zu entkoppeln, bieten sich mit dem JsTestDriver eine Reihe von Möglichkeiten, die Ihnen in den anderen vorgestellten Frameworks nicht zur Verfügung stehen. So existieren beispielsweise für verschiedene Entwicklungsumgebungen wie Eclipse oder WebStorm Plug-ins, über die Sie Ihre Unit Tests direkt aus der IDE heraus ausführen können und nicht erst in einen Browser wechseln müssen. Über das Plug-in können Sie aus Ihrer Entwicklungsumgebung heraus den JsTestDriver-Server starten, per Mausklick verschiedene Browser hochfahren und diese gleichzeitig mit dem Server verbinden. Auf diesen Browsern werden dann die Tests ausgeführt, die sowohl über ein Kontextmenü als auch über ein Tastenkürzel gestartet werden können. Auch die Ausgaben werden Ihnen innerhalb Ihrer Entwicklungsumgebung präsentiert. So erhalten Sie noch direkteres Feedback über den Status Ihrer Tests und müssen nicht für jeden Testlauf in eine andere Applikation wechseln.

Fazit

Alle hier vorgestellten Testframeworks haben ihre Vor- und Nachteile. So haben Sie mit Jasmine ein sehr mächtiges Werkzeug mit der Möglichkeit, Ihre eigenen Assertions zu definieren, mit Spies-Funktionen zu überwachen und sie zu beeinflussen. Der Nachteil von Jasmine ist, dass Sie im Normalfall einen Browser zur Ausführung Ihrer Tests benötigen. Durch die Kombination verschiedener Testframeworks können Sie diese Nachteile allerdings ausgleichen. Für den JsTestDriver existieren beispielsweise verschiedene Plug-ins, mit denen Sie in die Lage versetzt werden, die Infrastruktur, die Ihnen JsTestDriver zur Verfügung stellt, mit anderen Frameworks, wie QUnit oder Jasmine, zu nutzen. Damit können Sie Ihre Tests in der Syntax des jeweiligen Frameworks schreiben, müssen jedoch nicht auf die Integration in Ihrer Entwicklungsumgebung verzichten.

Eine weitere sinnvolle Komponente, die Sie in Ihren Tests verwenden können, ist Sinon.JS, eine unabhängige Bibliothek, die Spies, Stubs und Mocks für Ihre Tests zur Verfügung stellt. Die Funktionalität von Sinon.JS geht weit über die Möglichkeiten hinaus, die die Spies von Jasmine bieten. Unter anderem stellt Sinon.JS auch Objekte zur Verfügung, mit denen Sie AJAX-Calls abfangen und ihr Verhalten anpassen können. So werden Ihre Tests vollständig unabhängig von der Serverkomponente, und Sie können Ihre Tests auch in einer lokalen Umgebung ausführen, ohne sich darum kümmern zu müssen, dass Ihnen ein Server zur Verfügung steht, der die Anfragen eines Tests beantwortet.

Die vorgestellten Features und Konzepte sind nur ein Bruchteil der Möglichkeiten, die Ihnen beim Unit Testing von JavaScript-Applikationen zur Verfügung stehen. Sehen Sie diesen Artikel als einen Einstieg in die Qualitätssicherung, testen Sie verschiedene Frameworks und finden Sie das Set-up, das sich für Ihre Zwecke am besten eignet.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -