Continuous Integration für Webapps mit Java und JavaScript ist alles andere als trivial – gerade wenn viele Frameworks, zwei Programmiersprachen und verschiedene Browser ins Spiel kommen. In diesem Artikel zeige ich dir eine konkrete Lösung, wie du mit Jenkins, Maven und Node.js eine komplette CI-Umgebung aufbaust, die sowohl Unit- als auch End-to-End-Tests automatisiert.
Blogartikel lesenDieser Beitrag erläutert, wie Continuous Integration für Webapps basierend auf Java und javaScript umgesetzt werden kann. Neben dem Prozess des Continuous Integration (CI) wird eine konkrete Lösung für die Umsetzung des Prozesses mit der Software Jenkins präsentiert. Die verteilte Architektur, zwei Programmiersprachen, viele Frameworks und verschiedene Browser als Zielsysteme erzeugen eine nicht unerhebliche Komplexität.
Da die praktische Einrichtung von CI in diesem Setting nicht trivial ist und ein Überblick zu diesem Thema mir im Web bisher fehlte habe ich mich entschlossen, meine Konfiguration und das Zusammenspiel der beteiligten Software hier zu erläutern.
Je komplexer Software wird, desto mehr gewinnen Punkte wie die Abhängigkeiten zwischen ihren Bestandteilen und auch die Umgebung auf der eine Software getestet wird, an Bedeutung. Continuous Integration (kurz CI) kann (auch kleinen) Teams dabei helfen, den Überblick über den Entwicklungsstand der eigenen Software zu behalten. Im einfachsten Fall werden einzelne Module der Software nach Änderungen kompiliert und stehen bei Erfolg auf dem CI-Server bereit.
Darauf aufbauend können Abhängigkeiten zwischen den vorhandenen Modulen aufgelöst und ähnlich einem an den Kunden ausgelieferten Release eine ausführbare Version erstellt werden. Idealerweise ist dabei neben der Kompilierbarkeit der Software auch sichergestellt, dass die Software den an sie gestellten Anforderungen entspricht und somit „das richtige tut“.
Dies lässt sich dadurch überprüfen, dass zunächst Tests für die von der Software bereitgestellten Funktionalität geschrieben wurden und diese im Rahmen des CI-Prozesses im Anschluss an die Kompilierung der Software ausgeführt werden. Bei den Tests sind Unit-Tests und End-to-End-Tests zu unterscheiden.
Während erstgenannte möglichst atomare Bestandteile der Softwarefunktionalität testen und sich etwa im Rahmen eines testgetriebenen Entwicklungsmodells als Spezifikation für die zu entwickelnde Software verwenden lassen. End-to-End-Tests hingegen sind auf die Überprüfung der Gesamtapplikation unter Nutzung der Benutzeroberfläche (UI) ausgerichtet.
Sobald in einem der genannten Schritte ein Fehler auftritt, sollte der für die Änderung verantwortliche Entwickler sowie der/die Verantwortliche(n) der betroffenen Softwareteile bzw. des Gesamtprodukts darüber in Kenntnis gesetzt werden, um Fehler zu korrigieren. Idealerweise wissen somit die Mitglieder des Teams jederzeit darüber Bescheid, ob die von Ihnen verantwortete Funktionalität korrekt umgesetzt wurde und ein lauffähiger Zustand des Gesamtprodukts gegeben ist.
Zu einer Automatisierung dieser Aufgaben zu gelangen, ist je nach eingesetztem Technologiestack des eigenen Produkts nicht unbedingt trivial. In diesem Beitrag möchte ich daher einen Überblick geben, wie eine CI-Lösung für Web-Applikationen auf Basis von Java 8 auf Serverseite und HTML5 / Javascript auf Clientseite aussehen kann. Der Artikel gibt eine Übersicht über eine funktionsfähige CI-Lösung auf Basis nicht-proprietärer Komponenten.
CI ist ein etabliertes Prinzip und wird entsprechend von diversen Softwareprodukten unterstützt. Spannend wird es im Rahmen der Produktauswahl, wenn mehr als eine Basistechnologie eingesetzt wird, wie die hier besprochene Kombination von in Java geschriebener Serverlogik und ein Javascript Rich Client.
Die Automatisierung des Builds für dieses Setting erfolgt in diesem Artikel unter Verwendung des CI-Servers Jenkins, des Buildmanagement-Tools Maven und den node.js Paketen karma, protractor und grunt. Haben Sie also Bedarf an einer CI-Lösung, so können sie die hier vorgestellte aufgrund der ausgewählten Komponenten direkt selbst aufbauen und konfigurieren.
Um Ihnen die einzelnen Bestandteile des CI-Softwarestacks näherzubringen, möchte ich sie Ihnen im Folgenden kurz vorstellen. Das Versions- und Änderungsmanagement erfolgt im Rahmen des Artikels mittels eines git-repositories. Java-Quellcode wird mit JUnit, Javascript mit in jasmine-Syntax verfassten Unittests über den Testrunner karma getestet. Das node.js Paket protractor dient schließlich der Ausführung der End-to-End-Tests. Bevor wir die Kombination dieser Bestandteile innerhalb des CI-Prozesses betrachten, hier eine Übersicht mit den Bezugsquellen der Softwarekomponenten.
jenkins: Bei jenkins handelt es sich um einen nicht-proprietären CI-Server, welcher über Plugins erweitert werden kann.
Maven 3.3 wird zur Verwaltung von Abhängigkeiten zwischen unseren Softwaremodulen und externen Programmbibliotheken sowie für die übergeordnete Steuerung des Bauvorganges verwendet. Dabei werden folgende Plugins eingesetzt:
JUnit übernimmt schließlich die Ausführung von Unit-Tests für die serverseitige Java-Programmlogik.
node.js stellt eine Javascript runtime dar, welche diverse Pakete für die Durchführung von Unit-Tests sowie End-to-End-Tests bereitstellt. Während des CI-Prozesses wird eine node.js Umgebung eingerichtet, welche den Download der benötigten Pakete erlaubt:
Für den Aufbau der CI-Umgebung ist also eine nicht unerhebliche Zahl an Softwarekomponenten erforderlich. Im nächsten Schritt sind diese sinnvoll miteinander zu verknüpfen, um den CI-Prozess von der Feststellung einer Softwareänderung, über die Schritte Build und Test bis hin zum Reporting zu realisieren. Die folgende Abbildung gibt einen ersten Überblick über das Zusammenwirken innerhalb des CI-Softwarestacks. Die einzelnen Schritte werden anschließend kurz erläutert.
Mit den genannten Komponenten und Ihrer Kombination innerhalb des auf Jenkins und Maven basierenden CI-Prozesses lassen sich Projekte, welche sowohl Java als auch Javascript verwenden vollumfänglich automatisiert testen und deployen. Die detaillierte Konfiguration der einzelnen Komponenten werde ich in zukünftigen Artikeln behandeln.
Der Artikel beschreibt eine vollständige Continuous-Integration-Lösung für Webanwendungen mit Java-Backend und JavaScript-Frontend. Anhand von Jenkins, Maven und Node.js wird gezeigt, wie Builds, Unit-Tests und End-to-End-Tests automatisiert ablaufen können.