JavaScript testen – Testumgebung und Auswahl des Frameworks

24. August 2015

Das Ausführen von manuellen Tests reicht heutzutage nicht, um die gesamte Komplexität der Anwendung abzudecken. Es sollte die Aufgabe der Entwickler sein, um sicherzustellen, dass die Funktionalität die implementiert wird, tatsächlich funktioniert. Die Testfälle sollten vor allem automatisch reproduzierbar sein. Um dieses Ziel zu erreichen kommen Unit Tests zum Einsatz. In JavaScript sollten sie besonders von Bedeutung sein, da die Sprache über keine strenge Typisierung verfügt. Immer mehr Logik wird clientseitig implementiert, deshalb ist die Komplexität der Webanwendungen heutzutage signifikant gestiegen.

Gliederung des Testframeworks

In JavaScript existiert eine große Menge der Bibliotheken und Testframeworks. Es ist nämlich ganz wichtig das entsprechende Testframework fürs Projekt zu wählen. Die Testframeworks oder genauer gesagt die Konzepte der Testumgebung kann man nach drei Kategorien gliedern:

  • Clientseitige Frameworks – sind Frameworks, die nur den Webbrowser zum Funktionieren brauchen. Beispiele: Jasmine, QUnit
  • Serverseitige Frameworks – sind Frameworks, die die Serverkomponente zum Ausführen von Tests brauchen. Beispiel: JSTestDriver
  • Hybride Lösungen – ein clientseitiges Testframework und zusätzlich ein Testrunner, der als Serverkomponente dient. Beispiele: Jasmine oder QUnit mit Karma

Clientseitige Frameworks: QUnit und Jasmine

Zu den gängigsten clientseitigen Frameworks gehört QUnit und Jasmine. QUnit wurde von denselben Entwicklern gebaut, die JQuery implementiert haben. Am Anfang war also die Bibliothek ganz stark mit JQuery verbunden. Jetzt hat sich das geändert, und QUnit ist ein separates Framework für das Unit Testing. Die Tests werden so gebaut, wie in den anderen „klassischen“ Unit Tests Frameworks. Die Lernkurve sollte in diesem Fall ziemlich gering sein.

   1: test('Divide 4 by 2', function () {

   2:     var result = divide(2,2);

   3:     equal(result, 2, '4 divided by 2 equals 2');

   4: });

Der Testfall wird in der Funktion test() ausgeführt und die Prüfung findet in equal() statt.

Jasmine ist hingegen ein BDD (Behaviour Driven Development Framework) Testframework. Der Unterschied an den man sich gewöhnen sollte, ist die deskriptive Art und Weise, wie man die Tests schreibt.

   1: describe("calulates discount for tablets", function() {

   2:  

   3:     it("returns 10% discount for 2 items", function () {

   4:  

   5:         // Arrange

   6:         var product = new Product("Test", "Tablets", 10, 2);

   7:  

   8:         // Act

   9:         var result = App.Logic.dicountCalculator.calculateForProduct(product);

  10:  

  11:         // Assert

  12:         expect(result.hasDiscount()).toBe(true);

  13:         expect(result.newPrice).toBe(18);

  14:     });

  15:  

Describe() ist eine Funktion, die die Tests gruppiert. Ein bestimmter Testfall sollte in der it() Funktion implementiert werden.

Jasmine erfreut sich sehr großer Popularität und wird ständig um neue Funktionalitäten erweitert. Ein großer Vorteil von Jasmine ist, dass es sich gut für das Testen von AngularJS eignet. Der Umfang der Funktionalität ist bei beiden Frameworks fast gleich. Der Entwickler muss selber entscheiden, welche Art der Syntax für ihn mehr überzeugend ist.

Das Problem bei der Entwicklung von JavaScript ist, dass der Code in mehreren Browsern lauffähig sein sollte. Die clientseitigen Frameworks verfügen zwar über eine angenehme Syntax aber das Ausführen von Tests lässt sich alleine damit schwierig automatisieren.

Serverseitige Frameworks und Hybride Lösungen

Diese Möglichkeit wird zwar von den serverseitigen Frameworks angeboten, aber sehr oft müssen die Tests in demselben Framework geschrieben werden, das die Serverkomponente unterstützt. Wenn man aber von beiden Optionen profitieren möchte, dann kann ein clientseitiges Testframework und zusätzlich eine Serverkomponente benutzt werden, die nur zum Ausführen von Tests dient und gleichzeitig mehrere clientseitige Testframeworks unterstützt, wie zum Beispiel Karma. Karma ist ein Testrunner, der auf node.js basiert.

Die Funktionsweise der Testumgebung wurde in der folgenden Abbildung dargestellt.

image

Serverseitige Testumgebung für JavaScript

Das zentrale Element der Testumgebung ist der Server, der über die Config Datei konfiguriert ist. Der Server gibt eine Schnittstelle frei, mit der sich die Browser verbinden. Auf den verbundenen Browser werden die Tests ausgeführt. Der ganze Prozess wird mit der Kommandozeile gesteuert.

Von Installation bis zum Ausführen von Tests ist der Entwickler nur ein paar Schritte entfernt.

   1: # Installation von Karma:

   2: $ npm install karma --save-dev

   3:  

   4: # Installation von Plugins, die in der Testumgebung benutzt werden:

   5: $ npm install karma-jasmine karma-chrome-launcher --save-dev

   6:  

   7: # Starten von Karma mit einer bestimmten Konfigurationsdatei:

   8: $ karma start my.conf.js

imageAnzeige welche Browser mit dem Browser verbunden sind

image

Ergebnis der Ausführung von Tests

In Hinblick darauf, dass Karma sich ganz gut mit dem CI-Server verbinden lässt, scheint die gleichzeitige Anwendung des clientseitigen Testframeworks und der serverseitige Komponente eine vernünftige Lösung zu sein. Der nächste Schritt nach der Auswahl von Technologien ist die Erstellung einer testfreundlichen Architektur der Applikation.

Quellen:

[1] https://code.google.com/p/js-test-driver/

[2] http://karma-runner.github.io/0.12/index.html

[3] http://jasmine.github.io/

[4] https://qunitjs.com/

[5] Sebastian Springer, Testgetriebene Entwicklung mit JavaScript, dpunkt Verlag, 2015