Agiles Testen von JIRA Plugins (Teil 4): CI Server Integration und Code Coverage

Keine Kommentare

In den letzten drei Artikeln der Serie haben wir – das sind Raimar Falke und ich – uns auf das Schreiben von verschiedenen Arten von Tests konzentriert und dabei auch gezeigt, wie man sie ausführt. Tests in der lokalen Entwicklungsumgebung auszuführen ist aber nur der erste Schritt. Der wichtigere besteht darin, sie automatisch und regelmäßig in einem Continuous Integration (CI) Server laufen zu lassen. Dieser Artikel beschäftigt sich nun mit der Frage, was dabei zu beachten ist.

Hinweis: Dies ist eine 4-teilige blog Serie. Agiles Testen von JIRA Plugins (Teil 1), Wired Tests (Teil 2), Systemtests (Teil 3), CI Server Integration und Test Coverage (Teil 4). Darüber hinaus finden Sie auch eine Einführung zum Thema JIRA mit Plugins erweitern in unserem blog.

CI Server und das Atlassian SDK

Es gibt eine Vielzahl von CI Servern, aus denen man wählen kann. Zwei Berichten zufolge sind Jenkins (+Hudson), Bamboo und TeamCity die populärsten darunter. Während Jenkins und Hudson Open Source sind, sind Bamboo und TeamCity kommerzielle Produkte. Allen gemeinsam ist, dass sie Webapplikationen sind, die man selbst betreiben kann. Es existieren jedoch auch zahlreiche Unterschiede, beispielsweise bei den unterstützten SCM- und Buildsystemen. Große Unterschiede liegen auch in der Benutzeroberfläche.

Da bei JIRA Maven als Buildsystem zum Einsatz kommt, ist die Unterstützung von Maven die wichtigste Anforderung an den CI Server. Glücklicherweise ist das bei allen vier betrachteten Produkten der Fall.

Das Atlassian SDK in den 4.* Versionen benutzt allerdings Maven 2.1. Diese Version ist stark veraltet und einige der von uns genutzten Build-Plugins benötigen eine neuere Maven Version. Der Einsatz einer neueren Version ist zum Glück möglich (wir hatten das im ersten Artikel geschildert), aber nicht ganz einfach. Mittlerweile hat Atlassian jedoch die Version 5 des SDK veröffentlicht (im Juli 2014), die mit Maven in der Version 3.2.1 ausgeliefert wird. Dies vereinfacht die Einrichtung des Projektes im CI Server dramatisch, trotzdem bleibt die Konfiguration von Maven die größte Aufgabe.

Bamboo

Bei Bamboo gibt es verschiedene Wege, Maven für ein JIRA Projekt einzurichten:

  1. Man erstellt eine Konfiguration für ein Maven-Executable und gibt den Pfad auf die dem SDK beiliegende Maven-Installation an (z.B. …/atlassian-plugin-sdk-5.0.3/apache-maven-3.2.1). Zusätzlich ist es notwendig, die Umgebungsvariable ATLAS_HOME an die Build-Task Konfiguration zu übergeben und auf das Atlassian SDK (…/atlassian-plugin-sdk-5.0.3/) zeigen zu lassen.
  2. Da Bamboo das mvn Executable ausführt, welches selbst nur ein Shell-Skript ist, ist es auch möglich, das Skript anzupassen, sodass die Umgebungsvariable dort gesetzt wird, indem man die Zeile “export ATLAS_HOME=…/atlassian-plugin-sdk-5.0.3/” einfügt. Damit entfällt das Setzen der Umgebungsvariable in der Build-Task in der vorigen Variante.
  3. Es ist außerdem möglich, das vom SDK gelieferte atlas-mvn als mvn Executable zu verwenden. Dazu muss ein Verzeichnis erstellt werden (z.B. …/wrapper/), welches ein Verzeichnis bin erhält, in dem ein symbolischer Link namens mvn erzeugt wird, der auf das atlas-mvn Kommando verweist, z.B. …/atlassian-plugin-sdk-5.0.3/bin/atlas-mvn. In Bamboo muss dann ein Maven-Executable erstellt werden, dass auf den neuen Pfad (…/wrapper) verweist.

Bamboo

Jenkins

Jenkins benutzt nicht das mvn Executable, um den Maven Build auszuführen. Daher ist von den bei Bamboo vorgestellten Varianten nur die erste umsetzbar. Dazu muss zunächst die Umgebungsvariable ATLAS_HOME in der globalen Konfiguration mit dem Wert …/atlassian-plugin-sdk-5.0.3/ eingetragen werden. Zusätzlich muss eine Maven Installation konfiguriert werden, deren MAVEN_HOME auf das Verzeichnis …/atlassian-plugin-sdk-5.0.3/apache-maven-3.2.1/ verweist. Leider ist es nicht möglich, das EnvInject Plugin zu nutzen, um die global definierte Variable ATLAS_HOME in die einzelnen Builds zu übernehmen (siehe auch https://issues.jenkins-ci.org/browse/JENKINS-17620 bzw. https://issues.jenkins-ci.org/browse/JENKINS-18234).

Jenkins

TeamCity

TeamCity benutzt ebenso wie Jenkins nicht das mvn Executable. Die Umgebungsvariable ATLAS_HOME kann entweder auf Projekt- oder Buildebene konfiguriert werden. Im Maven Buildschritt muss die „Custom“ Maven Option gewählt werden und der Pfad …/atlassian-plugin-sdk-5.0.3 übergeben werden.

teamcity

Eine bessere Lösung?!

Es gibt verschiedene weitere Lösungen, wie man Maven und das Atlassian SDK in einem CI Server zusammenbringen kann. Dies sind:

  1. Die Umgebungsvariable ATLAS_HOME kann vor dem Start des CI Servers gesetzt werden. Dies hat den Nachteil, dass einige zusätzliche Schritte notwendig sind, wenn man eine andere Version des SDK im gleichen CI Server benutzen will (Stop/Anpassen/Start), d.h. es ist nicht mehr einfach möglich, den gleichen Test mit verschiedenen SDK Versionen laufen zu lassen.
  2. Die Umgebungsvariable ATLAS_HOME ist im Prinzip nur notwendig, um in den mitgelieferten Maven Einstellungen (…/atlassian-plugin-sdk-5.0.3/apache-maven-3.2.1/conf/settings.xml) die Referenz auf das mitgebrachte Repository (…/atlassian-plugin-sdk-5.0.3/repository/) aufzulösen. Eine Möglichkeit wäre daher, die Referenz in den Einstellungen explizit aufzulösen. Danach wird die Variable nicht mehr benötigt.

Allgemein empfehlen wir die zweite Variante. Am sichersten ist es dabei, eine Kopie des SDK anzulegen, in dem man die Variable expandiert. Auf diese Weise hat man das „Original“ immer noch zur Hand, wenn man auf Probleme stößt.

Sonst noch was?

Ja, leider gibt es noch einige weitere Punkte, die man berücksichtigen sollte.

Schwache CI Server

Auf einer Maschine, die erheblich weniger Rechenleistung hat als eine übliche Developer-Workstation (bspw. eine AWS Instanz), kann es sein, dass der Start von JIRA (für die Integrationstests) zu lange dauert und das System in einen Timeout läuft. Hier hilft es, den Wert der Einstellung atlassian.plugins.enable.wait hochzusetzen:

<plugin>
  <groupId>com.atlassian.maven.plugins</groupId>
  <artifactId>maven-jira-plugin</artifactId>
  <version>${amps.version}</version>
  <extensions>true</extensions>
  <configuration>
    <jvmArgs>-Datlassian.plugins.enable.wait=1000</jvmArgs></configuration></plugin>

Hinweis: Diese Einstellung führt zu Warnungen im Log, die darauf hinweisen, dass die Plugins nicht mit einem derartigen Timeout konfiguriert wurden. Diese Warnungen können natürlich ignoriert werden, da die Einstellung nur im Rahmen der Integrationstests und nicht im ausgelieferten Plugin gesetzt ist.

Ausführen von WebUI Tests

Die Integration von WebUI Tests in einem CI Server ist aufwändiger als bei anderen Testtypen. Das liegt vor allem daran, dass durch bzw. für den Test zusätzlich ein Browser gestartet und gesteuert werden muss. Und auf einem CI Server, der unter Linux läuft, bedeutet das, es muss ein X11 Server laufen. Da Linux Server normalerweise headless (also ohne GUI) laufen, wird üblicherweise ein virtuelles Ausgabegerät (virtual framebuffer, Xvfb) benutzt.

Obwohl AMPS die Option anbietet, den Xvfb für WebUI Tests automatisch zu starten, ist es uns nicht gelungen, dies auf unserem CI Server zum Laufen zu bringen. Die Alternative, die man hier wählen kann, besteht darin, Xvfb vorher zu starten (z.B. beim Systemstart im Rahmen eines Startskriptes) und beim Test zu benutzen. Für die Tests sollte dann auch die Umgebungsvariable DISPLAY gesetzt werden, bspw. auf “:1.0”.

Und was ist mit Code Coverage?

Wir benutzen Sonar als zentrales Dashboard für die Qualität des Quellcodes. Besonders, wenn man Legacy Code übernommen hat, ist es wichtig zu wissen, welche Klassen eigentlich wie gut getestet sind. Code Coverage kann hier als ein Indikator dienen. Trotzdem ist es natürlich auch wichtig sich die Tests anzuschauen, bspw. ob die vorgenommenen Prüfungen auch die funktionalen Anforderungen abbilden.

Im SDK wird bereits Clover, ein kommerzielles Code Coverage Tool von Atlassian, mitgeliefert. Als Ausgangspunkt für die eigene Arbeit kann das Kommanso atlas-clover dienen, welches von der Kommandozeile aus gestartet werden kann. Es instrumentiert zunächst den Quellcode des Plugins, führt Unit- und Integrationstests aus und erzeugt einen kurzen Überblick sowie einen HTML-Bericht in target/site/clover. Dazu benutzt es normale Maven Kommandos sowie zwei zusätzliche Clover spezifische Goals vor bzw. nach der Testausführung: clover2:setup und clover2:clover. Sonar selbst benutzt ebenfalls zwei Schritte für die Ausführung, was sehr gut passt. Am Ende haben wir zwei Builds im CI Server definiert, die nacheinander ausgeführt werden:

clean clover2:setup verify

und

clover2:clover sonar:sonar

Dadurch ist es möglich, die Code Coverage sowohl von Unit- als auch Integrationstests zu ermitteln. Andere Tools, wie bspw. JaCoCo und Cobertura liefern ebenfalls die Coverage von Unittests, scheiterten jedoch bei unseren Bemühungen, die Code Coverage der Integrationstests ebenfalls zu ermitteln.

Zusammenfassung

Wie man sieht, schreiben wir gern Tests und wir betrachten (automatisierte) Tests als wichtigen Bestandteil der Softwareentwicklung. Wir haben aber auch festgestellt, dass das Testen von JIRA Plugins manchmal umständlicher oder komplizierter ist, als es sein sollte. Ausgestattet mit den Informationen und Hinweisen aus diesen Artikeln gibt es eigentlich keine Ausrede mehr keinen CI Server für den Test eines JIRA Plugins einzusetzen.

Da wir aktuell keine weiteren offenen Themen bzgl. des Testens von JIRA Plugins haben, schließen wir mit diesem Artikel unsere Serie ab.

Wir hoffen, wir konnten helfen und sind bei Fragen und Problemen gern da. Über Anregungen und Ergänzungen würden wir uns ebenso freuen.

Thomas Strecker

Thomas Strecker ist als Senior IT Consultant bei der codecentric AG tätig und leitet mit Marcel Wolf den Standort Berlin. Neben seiner Führungsarbeit beschäftigt er sich in Projekten weiterhin mit Themen wie Java Profiling und Performance-Analyse, Microservices oder auch Testautomatisierung im Kontext agiler Softwareentwicklung.

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.