Automating JMeter tests with Maven and Jenkins - codecentric AG Blog

:

In this post, I will show how to integrate the popular load testing tool JMeter in a Maven build. The goal is to allow every developer to easily develop and execute JMeter tests on his local machine. There will be no need to learn a new commandline utility or to install separate tools. Everything will be possible via some simple maven goals. With this setup, it is also easy to create a Jenkins job, that allows execution of JMeter tests against a testing environment with a single click.

Integrating JMeter with Maven

There are two plugins, that allow integration of JMeter tests in a Maven build: jmeter-maven-plugin and chronos-maven-plugin. Which plugin to choose, depends on the requirements. For me, the following points were important:

  1. The plugin should not depend on a local JMeter installation.
  2. It must be possible to start the JMeter test from command line (without gui).
  3. The JMeter GUI should also be accessibla directly via the plugin (e.g. via a separate Maven goal).
  4. It should be possible to include the JMeter Plugins.
  5. The plugin should generate meaningful reports (or there must be some other possibility to generate these reports).

Points 1) to 3) are satisfied by both plugins. The reporting is always a matter of taste. The chronos plugin comes with an additional reporting plugin, the chronos-report-maven-plugin, that embeds test results in a Maven report. There is also a jmeter-analysis-maven-plugin, which creates a simple html report with graphs showing response times over time. What finally motivated my decision to go for the jmeter-maven-plugin, was the last point. With the jmeter-maven-plugin, a simple additional dependency to kg.apc:jmeter-plugins allowed using the JMeter Plugins in GUI as well as in headless mode. I couldn’t find a similar possibility in the jmeter-chronos-maven-plugin.

The following code- and configuration-snippets are taken from the example project jmeter-maven-example, which is available on GitHub. There is also a public jenkins with a simple job, that allows executing JMeter tests against a real application (hosted on CloudBees).

Because the public jenkins hibernates after 15 days, I also added a docker build for a preconfigured jenkins to the github repo. Just see the README.md for an explanation how to build and start the jenkins docker image.

The configuration of this jenkins job is explained in the following sections. But first, the necessary Maven configuration:

<plugin>
  <groupId>com.lazerycode.jmeter</groupId>
  <artifactId>jmeter-maven-plugin</artifactId>
  <version>1.8.1</version>
  <configuration>
    <!--
       By default the test results are saved in a file  
       /target/jmeter/results/<testname>-<timestamp>.jtl
       Further processing is easier without timestamp though.
    -->
    <testResultsTimestamp>false</testResultsTimestamp>
 
    <!--
       To simplify debugging, it is advisable to adapt the loglevel.
       The jmeter logs are written to the file jmeter.log.
    -->
    <overrideRootLogLevel>DEBUG</overrideRootLogLevel>
 
    <!--
       By default, the console output during a jmeter test run is suppressed.
       We want to display the progress using the listener "Generate Summary Results" 
       (which periodically prints stats to stdout). Therefore we have to make sure,
       that the jmeter output is not suppressed.
    -->
    <suppressJMeterOutput>false</suppressJMeterOutput>
 
    <!--
       If tests fail (e.g. a http-request running into a timeout), the corresponding maven
       goal also fails (and subsequent goals aren't executed anymore). We want to create graphs
       from test-results, no matter if some requests failed or not, so we ignore jmeter failures.
    -->
    <ignoreResultFailures>true</ignoreResultFailures>
  </configuration>
  <dependencies>
    <dependency>
      <groupId>kg.apc</groupId>
      <artifactId>jmeter-plugins</artifactId>
      <version>1.0.0</version>
      <exclusions>
         <!--
            Unfortunately some transitive dependencies cannot be found on mvncentral
            and we have to explicitly exclude them.
            For a complete list, see https://github.com/mlex/jmeter-maven-example/
        -->
        <exclusion>
            <groupId>kg.apc</groupId>
            <artifactId>perfmon</artifactId>
        </exclusion>
        <!-- ... -->
 
        <!--
            Because of a bug in the jmeter-maven-plugin (see 
            https://github.com/Ronnie76er/jmeter-maven-plugin/issues/77) we have to
            exclude jmeter dependencies here, too.
        -->
        <exclusion>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>jorphan</artifactId>
        </exclusion>
        <!-- ... -->
      </exclusions>
    </dependency>
  </dependencies>
</plugin>

<plugin> <groupId>com.lazerycode.jmeter</groupId> <artifactId>jmeter-maven-plugin</artifactId> <version>1.8.1</version> <configuration> <!-- By default the test results are saved in a file /target/jmeter/results/<testname>-<timestamp>.jtl Further processing is easier without timestamp though. --> <testResultsTimestamp>false</testResultsTimestamp><!-- To simplify debugging, it is advisable to adapt the loglevel. The jmeter logs are written to the file jmeter.log. --> <overrideRootLogLevel>DEBUG</overrideRootLogLevel><!-- By default, the console output during a jmeter test run is suppressed. We want to display the progress using the listener "Generate Summary Results" (which periodically prints stats to stdout). Therefore we have to make sure, that the jmeter output is not suppressed. --> <suppressJMeterOutput>false</suppressJMeterOutput><!-- If tests fail (e.g. a http-request running into a timeout), the corresponding maven goal also fails (and subsequent goals aren't executed anymore). We want to create graphs from test-results, no matter if some requests failed or not, so we ignore jmeter failures. --> <ignoreResultFailures>true</ignoreResultFailures> </configuration> <dependencies> <dependency> <groupId>kg.apc</groupId> <artifactId>jmeter-plugins</artifactId> <version>1.0.0</version> <exclusions> <!-- Unfortunately some transitive dependencies cannot be found on mvncentral and we have to explicitly exclude them. For a complete list, see https://github.com/mlex/jmeter-maven-example/ --> <exclusion> <groupId>kg.apc</groupId> <artifactId>perfmon</artifactId> </exclusion> <!-- ... --><!-- Because of a bug in the jmeter-maven-plugin (see https://github.com/Ronnie76er/jmeter-maven-plugin/issues/77) we have to exclude jmeter dependencies here, too. --> <exclusion> <groupId>org.apache.jmeter</groupId> <artifactId>jorphan</artifactId> </exclusion> <!-- ... --> </exclusions> </dependency> </dependencies> </plugin>

The tests must be placed in the folder /src/test/jmeter. The JMeter GUI can be started with mvn jmeter:gui. There you can edit and execute tests. With mvn jmeter:jmeter is it possible to execute tests without GUI. In headless mode the JMeter listener Generate Summary Results is great to display progress information (via simple console output).

The tests are most likely executed in various envorinments. It is good practice to have a central point, where you can store the configurations for the different environments. The easiest way is to use Maven properties and profiles. The example project defines two different Maven profiles, one for local execution and one for execution from jenkins. The Maven properties are passed to JMeter via the userProperties option. Inside a JMeter test, you can then access the properties using the function ${__P(propertyName)}.

<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>

<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>

Executung JMeter tests with Jenkins-CI

Now that we have different Maven profiles for the various environments, the configuration of an appropriate Jenkins job is just a small step. The parameterized builds are another nice feature of Jenkins, that is very useful for JMeter tests. Parameters can be used for example, to allow users to define the size of the load test (that is: the number of threads and iterations).

Jenkins Job für JMeter Test

Reporting

What meaningful reporting looks like, always depends on the concrete requirements. Sometimes it makes sense to regularly run equally sized load tests, so that you get instant feedback whenever a change in the system considerably effects performance. In this case, the Jenkins Performance Plugin is a good choice. However, I was more interested in graphs that show the system behaviour over time. Those graphs can be easily created from command line using the CMDRunner tool of JMeter Plugins. With the help of a small Maven plugin, the jmeter-graph-maven-plugin, it is possible to easily integrate this graph-generation in a Maven build.

Result

Just let the images speak for themselves. Starting the job with one click, …
start-jmeter-job
… defining test properties (like number of threads), …
size-jmeter-job
… running the test …
watch-jmeter-job
… and finally displaying the test results couldn’t be much easier.
jmeter-job-result