Single Page Applications mit AngularJS, Teil 3: Unit-Testing

Da bei modernen Webanwendungen viel Logik mit JavaScript implementiert wird, liegt der Wunsch nahe, diese Codebereiche automatisiert zu überprüfen. Für das Testen von AngularJS-Anwendungen bietet sich Jasmine an.

In Pocket speichern vorlesen Druckansicht
Lesezeit: 17 Min.
Von
  • Manfred Steyer
Inhaltsverzeichnis

Da bei modernen Webanwendungen viel Logik mit JavaScript implementiert wird, liegt der Wunsch nahe, diese Codebereiche automatisiert zu überprüfen. Für das Testen von AngularJS-Anwendungen bietet sich Jasmine an.

Jasmine ist ein Framework zum Implementieren von Unit-Tests, das die Ideen des Behavior Driven Development (BDD) unterstützt. Das bedeutet, dass jeder Testfall ein Verhaltensmerkmal der Anwendung beschreibt. Jasmine ist nicht von AngularJS abhängig und lässt sich auch sonst zum Testen von JavaScript-Code heranziehen.

Im Folgenden kommt es zum Testen von ViewModel und Controller zum Einsatz, und Beispiele zeigen, wie sich darüber hinaus die Testbarkeit von AngularJS-Anwendungen mit eigenen Services im Zusammenspiel mit Attrappen (Mock-Objekten) erhöhen lässt.

Testfälle befinden sich beim Einsatz von Jasmine innerhalb von Blöcken, die Nutzer als Test-Suiten bezeichnen und durch einen Aufruf der Methode describe definieren. Dazu nimmt letztere, wie der folgende einfache Test demonstriert, zwei Parameter entgegen. Beim ersten handelt es sich um die Beschreibung des erwarteten Verhaltens oder eines Teils davon. Der zweite Parameter repräsentiert eine Funktion, die den Test enthält. Innerhalb dieser können weitere Aufrufe von describe stattfinden, um das beschriebene Verhalten weiter zu konkretisieren. Auf die Weise lässt sich eine Hierarchie mit Anforderungen aufbauen. An deren Ende befinden sich die einzelnen Testfälle, die der Entwickler mit der Funktion it beschreibt.

describe("Object under test", function () {

beforeEach(function () {
});

afterEach(function () {
});

describe("when this", function () {

beforeEach(function () {
});

afterEach(function () {
});

describe("and when that", function () {

it ("sould do this", function () {
var objectUnderTest = { ok: true };
expect(objectUnderTest.ok).toBe(true);
});

it("should do that", function () {
var objectUnderTest = { notOk: false };
expect(objectUnderTest.notOk).toBe(false);

});
});
});
});

Genauso wie describe, erwartet it Angaben zur Konkretisierung des erwarteten Verhaltens und eine Funktion. Letztere enthält den Test. Abbildung 1 zeigt die Hierarchie, die das obige Beispiel auf diese Weise aufbaut und Jasmine bei der Ausführung ausgibt. Es handelt sich dabei, den Ideen von BDD folgend, um eine ausführbare Spezifikation. Die Tatsache, dass die untersten Ebenen dieser Hierarchie mit grüner Schrift präsentiert werden, deutet darauf hin, dass die damit assoziierten Tests erfolgreich ausgeführt wurden.

Ausgabe eines Jasmine-Tests (Abb.1)


Innerhalb der mit it definierten Testfälle führt der Entwickler Überprüfungen durch, um herauszufinden, ob der Testfall die gewünschten Ergebnisse erzielt hat. Der betrachtete Fall kontrolliert zum Beispiel mit

expect(objectUnderTest.ok).toBe(true)

ob die Eigenschaft objectUnderTest.ok den Wert true aufweist. Funktionen wie toBe sind im Jasmine-Jargon als Matcher bekannt. Deren Bedeutung lässt sich mit der Eigenschaft not umkehren:

expect(objectUnderTest.ok).not.toBe(true)

Neben toBe bringt Jasmine einige weitere Matcher, deren Namen Programm sind. Darunter befinden sich: toBeDefined, toBeNull, toBeNaN, toBeFalsy, toBeTruthy, toContain, toBeLessThan, toBeGreaterThan und toThrow. Daneben kann der Entwickler mit toMatch prüfen, ob ein Wert einem übergebenen regulären Ausdruck entspricht. Dem Umstand, dass Fließkommazahlen kleine Ungenauigkeiten aufweisen können, trägt der Matcher toBeCloseTo Rechnung. Er nimmt zwei Werte entgegen: jenen, der erwartet wird, und ein erlaubtes Delta. Informationen dazu findet man in der Dokumentation.

Mit beforeEach und afterEach registriert der Entwickler jeweils eine weitere Funktion, die vor oder nach sämtlichen Testfällen der aktuellen sowie der untergeordneten Ebenen der beschriebenen Hierarchie auszuführen sind.

Mehr Infos

Artikelserie zu AngularJS

Artikel 1: Erste Schritte
Artikel 2: Konzepte näher betrachtet
Artikel 3: Unit-Testing
Artikel 4: Validieren und Internationalisierung
Artikel 5: Routing und Deep-Linking

Um Jasmine-Tests auszuführen, ist ein Test Runner vonnöten. Der im Lieferumfang von Jasmine befindliche besteht lediglich aus einer HTML-Seite, die auf CSS- und JavaScript-Dateien von Jasmine verweist und ein wenig JavaScript-Code zum Ausführen der Tests enthält. Im Code der Seite referenziert der Entwickler die JavaScript-Dateien, die seine Tests beherbergen sowie all jene Dateien, die (direkte und indirekte) Abhängigkeiten der Tests enthalten.