JMeter Tests mit Maven und Jenkins automatisieren

1 Kommentar

Mein letzter Post war ein Appell an Entwickler, öfter auf Lasttests zurückzugreifen, um bereits während der Entwicklung mögliche (Performance-)Probleme in der Anwendung zu identifizieren. Die Hürde dabei ist oft nicht so sehr das mangelnde Interesse, sondern der Aufwand, den man betreiben muss, um einen Lasttest durchzuführen. In meinem letzten Projekt lagen zum Beispiel zwei sehr ausführliche JMeter Tests im Source-Code-Repository. Daneben lag eine etwas längliche README-Datei, in der beschrieben wurde, was alles nötig ist, um den Test durchzuführen. Von der Installation von JMeter (ok, das muss sein) über nötige Plugins und zusätzliche JARs (für den JUnit-Sampler) bis hin zu den nötigen Anpassungen der Konfiguration war ich eine gute Stunde beschäftigt. Von Versionsproblemen und dem Setup der Testdatenbank ganz zu schweigen.

Als Entwickler ist man es gewohnt, zu automatisieren, wo es nur geht. Das Lasttest-Tool JMeter ist hierbei keine Ausnahme. Idealerweise sollten JMeter Tests auf Knopfdruck ausgeführt werden können. Und das in jeder Umgebung: Lokal auf dem Entwickler-Laptop, vom Jenkins gegen ein Testsystem oder als ausgewachsener Lasttest mit verteilten Agenten gegen ein produktionsähnliches Staging-System. Am einfachsten lässt sich das erreichen, wenn man JMeter in den Maven-Build integriert. Wie das aussehen kann, werde ich in den nächsten Abschnitten zeigen.

Integration von JMeter in den Maven-Build

Für die Integration von JMeter in den Maven-Build gibt es zwei Plugins (zumindest habe ich nur diese beiden Plugins gefunden): jmeter-maven-plugin und chronos-maven-plugin. Bei der Wahl des Plugins waren mir die folgenden Anforderungen wichtig (das kann natürlich von Projekt zu Projekt unterschiedlich sein):

  1. Das Plugin soll nicht von einer lokalen JMeter-Installation abhängig sein. Wenn nötig muss JMeter automatisch heruntergeladen werden (woher auch immer).
  2. Es muss möglich sein, Tests von der Kommandozeile ohne GUI zu starten und die Testergebnisse an einem vordefinierten Ort abzulegen.
  3. Es muss ebenfalls möglich sein, die JMeter-GUI aus Maven heraus zu starten.
  4. Die Verwendung von JMeter-Plugins sollte einfach sein.
  5. Es muss eine Möglichkeit geben, sinnvolle Reports zu generieren.

Die ersten drei Punkte werden von beiden Maven-Plugins erfüllt. Beim Reporting kommt es immer auf die konkreten Anforderungen an. Für das Chronos Plugin gibt es ein zusätzliches Reporting-Plugin, das die Ergebnisse des Tests in einen Maven-Report einbettet. Ich war vor allem auf der Suche nach aussagekräftigen Graphen, weshalb ich den Benefit des chronos-reporting-plugins nicht so hoch einschätzte. Der vierte Punkt war letztendlich ausschlaggebend dafür, dass meine meine Wahl auf das jmeter-maven-plugin fiel. Durch einfaches Hinzufügen einer Abhängigkeit zu kg.apc:jmeter-plugins waren die JMeter-Plugins sowohl im GUI wie auch im Headless Modus verfügbar. Diese Möglichkeit habe ich für das Chronos-Plugin nicht gefunden.

Die folgenden Code- und Konfigurationsschnipsel sind dem Beispiel-Projekt jmeter-maven-example entnommen. Für das Projekt existiert auch ein öffentlicher Jenkins, auf dem exemplarisch ein Job konfiguriert ist. Der Job erlaubt es, auf Knopfdruck JMeter Tests gegen eine echte (auf CloudBees gehostete) Anwendung durchzuführen. Die Konfiguration des Jenkins-Jobs wird weiter unten noch im Detail erklärt.

<plugin>
  <groupId>com.lazerycode.jmeter</groupId>
  <artifactId>jmeter-maven-plugin</artifactId>
  <version>1.8.1</version>
  <configuration>
    <!--
       Die Ergebnisse werden normalerweise in einer Datei 
       /target/jmeter/results/<TestName>-<TimeStamp>.jtl abgelegt. 
       Für die Weiterverarbeitung ist der Timestamp nur hinderlich.
    -->
    <testResultsTimestamp>false</testResultsTimestamp>
 
    <!--
       Für die Fehlersuche bewährt es sich anfangs das LogLevel hochzuschrauben.
       Die JMeter-Logs werden in die Datei jmeter.log geschrieben.
    -->
    <overrideRootLogLevel>DEBUG</overrideRootLogLevel>
 
    <!--
       Konsolen-Ausgaben des JMeter-Prozesses werden standardmäßig unterdrückt (warum auch 
       immer). Es wird aber explizit der Listener "Create Summary Results" verwendet, damit
       auf der Konsole der aktuelle Testfortschritt mitverfolgt werden kann.
    -->
    <suppressJMeterOutput>false</suppressJMeterOutput>
 
    <!--
       Wenn Tests fehlschlagen (z.B. HTTP-Requests in einen Timeout laufen), wird normalerweise
       auch das entsprechende Maven-Goal als fehlerhaft markiert (und nachfolgende Schritte nicht
       mehr ausgeführt). Im Beispiel sollen aber trotz Fehler Graphen erzeugt werden.
    -->
    <ignoreResultFailures>true</ignoreResultFailures>
  </configuration>
  <dependencies>
    <dependency>
      <groupId>kg.apc</groupId>
      <artifactId>jmeter-plugins</artifactId>
      <version>1.0.0</version>
      <exclusions>
         <!--
            Leider sind einige Abhängigkeiten nicht in mvncentral zu finden,
            deshalb müssen sie hier explizit ausgeschlossen werden.
            Für eine vollständge Liste, siehe https://github.com/mlex/jmeter-maven-example/
        -->
        <exclusion>
            <groupId>kg.apc</groupId>
            <artifactId>perfmon</artifactId>
        </exclusion>
        <!-- ... -->
 
        <!--
            Aufgrund eines Bugs im jmeter-maven-plugin (siehe 
            https://github.com/Ronnie76er/jmeter-maven-plugin/issues/77) müssen 
            JMeter-Abhängigkeiten auch ausgeschlossen werden.
        -->
        <exclusion>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>jorphan</artifactId>
        </exclusion>
        <!-- ... -->
      </exclusions>
    </dependency>
  </dependencies>
</plugin>

Die JMeter Tests werden einfach im Verzeichnis /src/test/jmeter abgelegt. Durch mvn jmeter:gui kann man die JMeter GUI starten. Dort kann man die Tests bearbeiten oder direkt aus der GUI heraus ausführen. Durch mvn jmeter:jmeter werden die Tests ohne GUI ausgeführt. Für diese Art der Ausführung eignet sich übrigens der JMeter Listener Create Summary Results um kontinuierlich (durch einfache Konsolenausgaben) über den Fortschritt des Tests informiert zu werden.

Damit die Tests problemlos auf unterschiedlichen Umgebungen ausgeführt werden können, ist es sinnvoll, die Konfiguration für diese Umgebungen irgendwo zentral abzulegen, zum Beispiel in einem Maven-Profil. Im Beispiel-Projekt sind auf diese Weise zwei Konfigurationen (für lokale Ausführung, sowie für Ausführung auf dem Jenkins) hinterlegt. Die Maven-Properties können über die userProperties Option des JMeter Maven Plugins an JMeter übergeben werden. Im JMeter Test kann man auf die Einstellungen dann mit Hilfe der Funktion ${__P(propertyName)} zugreifen.

<profiles>
  <profile>
    <id>local</id>
    <properties>
      <performancetest.webservice.host>localhost</performancetest.webservice.host>
      <performancetest.webservice.port>8080</performancetest.webservice.port>
    </properties>
  </profile>
  <profile>
    <id>jenkins</id>
    <properties>
      <performancetest.webservice.host>my.test.system</performancetest.webservice.host>
      <performancetest.webservice.port>80</performancetest.webservice.port>
    </properties>
  </profile>
  <build>
    <plugins>
      <plugin>
        <groupId>com.lazerycode.jmeter</groupId>
        <artifactId>jmeter-maven-plugin</artifactId>
        <version>1.8.1</version>
        <configuration>
          <propertiesUser>
            <webservice.host>${performancetest.webservice.host}</webservice.host>
            <webservice.port>${performancetest.webservice.port}</webservice.port>
          </propertiesUser>
        </configuration>
      </plugin>
    </plugins>
  </build>
</plugin>

JMeter Tests aus Jenkins heraus starten

Nachdem man bereits unterschiedliche Maven-Profile angelegt hat, ist die Konfiguration eines entsprechenden Jenkins-Jobs nicht mehr schwer. Interessant ist noch die Möglichkeit, auch den Umfang der Lasttests (d.h. die Anzahl der Threads und der Iterationen) über Maven-Properties festzulegen. Kombiniert mit einem parametrisierbaren Jenkins-Job erhält man so die Möglichkeit auf Knopfdruck unterschiedliche dimensionierte Lasttests zu starten.

Jenkins Job für JMeter Test

Reporting

Wie bereits erwähnt, kann man sich darüber streiten, wie „sinnvolles“ Reporting aussieht. Wie der Berater so schön sagt: „It depends“. Für regelmäßig durchgeführte, immer gleich dimensionierte Performance-Tests eignet sich das Performance Plugin für Jenkins. In meinem Fall war ich hauptsächlich an Graphen interessiert, die das Systemverhalten im zeitlichen Verlauf des Tests wiederspiegeln. Diese Graphen können auch ohne GUI mit dem CMDRunner der JMeter-Plugins erstellt werden. Mit einigem Verbiegen und dem exec-maven-plugin war es auch möglich, die Erstellung der Graphen in den Maven-Build zu integrieren. Die nötige Konfiguration sieht nicht sehr schön aus, deshalb beschränke ich mich an dieser Stelle auf einen Link zum Beispielprojekt. Ein Maven-Plugin, das die Erstellung der Graphen für JMeter Tests wesentlich vereinfacht, ist bereits in Arbeit: jmeter-graph-maven-plugin.

Ergebnis

Am besten lässt man Bilder sprechen. Vom Start …
start-jmeter-job
… über die Dimensionierung …
size-jmeter-job
… und den Testdurchlauf …
watch-jmeter-job
… bis zum übersichtlichen und leicht verständlichen Ergebnis …
jmeter-job-result
… sind es nur wenige Schritte. So einfach können Lasttests sein.

Michael Lex ist agiler Softwareentwickler bei codecentric. Neben der täglichen Arbeit mit Java EE oder Spring gilt sein besonderes Interesse dem weiten Feld der Datenanalyse, insbesondere Machine-Learning-Algorithmen.

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

Kommentare

Kommentieren

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