Performance Testing a Multiuser Web Application with JMeter and Maven

January 18th, 2015 by

When there is the need to create load tests or performance tests for an application, Apache JMeter is a handy tool and set up with ease.

In the following short tutorial I’d like to demonstrate how to configure JMeter to log into a Java EE web application with multiple users specified in a CSV file, how to generate some basic reports and how to integrate JMeter into a mavenized build using the JMeter Maven Plugin.

Adding an Aggregate Graph Report in JMeter

Adding an Aggregate Graph Report in JMeter

 

JMeter Download and Maven Dependencies

Apache JMeter may be obtained at the JMeter Download Site.

To enable our Maven build to run JMeter test plans, we only need to add the following dependency for the JMeter Maven Plugin to our pom.xml:

<plugin>
	<groupId>com.lazerycode.jmeter</groupId>
	<artifactId>jmeter-maven-plugin</artifactId>
	<version>1.10.0</version>
	<executions>
		<execution>
			<id>jmeter-tests</id>
			<goals>
				<goal>jmeter</goal>
			</goals>
		</execution>
	</executions>
</plugin>

Multiuser Java EE Web Application

We need some kind of web application with multi-user support. For this purpose we’re using the application from my tutorial: “Java EE: Setting up and Testing Form-Based JDBC Authentication with Arquillian and Maven” and we’re adding additional four users to the application:

Here is an excerpt from the initialization bean, for the full application sources, please feel free to skip to “Tutorial Sources“:

@Singleton
@Startup
public class ApplicationConfigurationBean {
	// creates 5 users: admin, ted, lisa, marge, bart
	private final String[] createUserStatements = {
		"INSERT INTO `users` VALUES('admin', 'test')",
		"INSERT INTO users_groups VALUES('administrators','admin')",
		"INSERT INTO `users` VALUES('ted', 'foo123')",
		"INSERT INTO users_groups VALUES('administrators','ted')",
		"INSERT INTO `users` VALUES('lisa', 'xyz123')",
		"INSERT INTO users_groups VALUES('administrators','lisa')",
		"INSERT INTO `users` VALUES('marge', 'redrum')",
		"INSERT INTO users_groups VALUES('administrators','marge')",
		"INSERT INTO `users` VALUES('bart', 'eatmyshorts')",
		"INSERT INTO users_groups VALUES('administrators','bart')"
	};
 
	@Resource(lookup = "jdbc/hascode_test_db")
	private DataSource ds;
 
	@PostConstruct
	protected void onStartup() throws SQLException {
		[..]
		for (String sql : createUserStatements) {
			con.prepareCall(sql).execute();
		}
		[..]
	}
}

Creating the Test Plan in JMeter

Now we’re ready to create a new test plan by starting JMeter and adding a new test plan.

Creating a new Thread Group

A thread group controls the number of threads JMeter will use to execute our test.

Each thread group represents a single user and therefor needs an isolated cookie manager to store the state of our HTTP connection.

We’re adding a new thread group with Numbers of Threads set to 20.

Creating a new thread group in JMeter

Creating a new thread group in JMeter

Adding a Cookie Manager

To this thread group, we’re adding a new cookie manager so that the authentication cookie from our web application is working but isolated in each thread.

Adding a cookie manager in JMeter

Adding a cookie manager in JMeter

Adding a CSV Datasource

As we have multiple users logging into our web application, we’re adding a CSV file containing username and password in the format <username>,<password>

This is our users.csv

admin,test
ted,foo123
lisa,xyz123
marge,redrum
bart,eatmyshorts

Each thread of the thread-group gets an entry from this datasource assigned, so it is important not to add the datasource as a child of the thread group but as a child of the test plan.

The configuration for this data source should look like this one:

Adding a CSV Datasource in JMeter

Adding a CSV Datasource in JMeter

Recording User Activity with the HTTP Test Script Recorder

The most comfortable way to record the test user’s interaction with our web application is to record everything using the HTTP Test Script Recorder and is done like this:

  • Add a HTTP Test Script Recorder to the Workbench
  • Configure the Recorder’s HTTP-Proxy
  • Configure your browser to use the Recorder’s Proxy
  • Start recording
  • Browse through the application
  • Fine-tune the recorded steps

The following screenshot shows the configuration of our HTTP Test Script Recorder.

It’s important to set out thread group as target controller so that the steps recorded are assigned to this unit.

Following redirects is necessary because the security layer in our web application redirects to the login form when not authenticated.

Adding a HTTP Test Script Recorder in JMeter

Adding a HTTP Test Script Recorder in JMeter

Setting up the Proxy

We’re setting the recorder’s HTTP proxy to run on port 9000 – the port should not interfere with the web application’s port.

Browser Configuration

Now we need to set this HTTP proxy in our browser.

Because switching between proxy servers is a common task for me, I’m using a Firefox addon, FoxyProxy here to switch between different proxy servers with one click or domain based.

The following screenshots displays a sample FoxyProxy configuration, otherwise simply add localhost and port 9000 to the regular proxy settings our your browser:

Proxy Configuration for Firefox with FoxyProxy

Proxy Configuration for Firefox with FoxyProxy

Recording

To start recording, we simply need to press “Start” in the Recorder screen in JMeter and then continue in our browser by accessing our web application.

For this demonstration we want to ..

  • Access the application’s start page
  • Log into the application
  • Access the URL where the current user’s information is displayed in the JSON format

After the run we should see several steps added to the thread group.

Login Configuration with CSV Data

Out CSV data-source provides us with the username and the password – we now simply need to add the placeholders for this local variable as parameters for the HTTP request where the authentication takes place.

The placeholders are ${username} and ${password} as specified by the CSV data-source configuration.

Login Configuration using CSV Data

Login Configuration using CSV Data

Adding Reports

Finally we may add some reports (Test Plan > Listeners > ..) customized to our needs:

Aggregate Graph

This is an example for an aggregate graph added to our test plan:

Adding an Aggregate Graph Report in JMeter

Adding an Aggregate Graph Report in JMeter

Aggregate Report

This is an example for a simple aggregate report added to our test plan

Adding simple Aggregate Report in JMeter

Adding simple Aggregate Report in JMeter

Adding Assertions

Finally we should add some assertions to the JMeter test..

Verifying the JSON Response

We’re verifying the response of the session REST service by adding a Response Assertion. For more complex JSON verification, there is a specialized JSON plugin for JMeter that might be helpful.

Assertion to verify the JSON Response.

Assertion to verify the JSON Response.

Duration Assertion

By adding this assertion to the thread group, we’re testing verifying the duration of a walk through the application for a single user (I used 2 seconds here, instead of 20ms!) :

Adding a Duration Assertion in JMeter

Adding a Duration Assertion in JMeter

Directory Structure

The following files have been added to our normal web project to enable JMeter with maven and add the test plan and the CSV file containing the user information:

.
├── pom.xml
└── src
    └── test
        └── jmeter
            ├── multiuser-profiling.jmx
            └── users.csv

Running JMeter with Maven

Running the test plan in the JMeter GUI is a nice thing but for a close integration into our mavenized build lifecycle, the JMeter Maven Plugin allows an execution with Maven like this:

mvn jmeter:jmeter
[INFO] ------------------------------------------------------------------------
[INFO] Building hascode 1.0.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- jmeter-maven-plugin:1.10.0:jmeter (default-cli) @ jmeter-multiuser-profiling ---
[INFO]
[INFO] -------------------------------------------------------
[INFO]  P E R F O R M A N C E    T E S T S
[INFO] -------------------------------------------------------
[INFO]
[INFO]
[info]
[debug] JMeter is called with the following command line arguments: -n -t /data/project/jmeter-multiuser-profiling/src/test/jmeter/multiuser-profiling.jmx -l /data/project/jmeter-multiuser-profiling/target/jmeter/results/20150118-multiuser-profiling.jtl -d /data/project/jmeter-multiuser-profiling/target/jmeter -j /data/project/jmeter-multiuser-profiling/target/jmeter/logs/multiuser-profiling.jmx.log
[info] Executing test: multiuser-profiling.jmx
[info] Completed Test: multiuser-profiling.jmx
[INFO]
[INFO] Test Results:
[INFO]
[INFO] Tests Run: 1, Failures: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.814s
[INFO] Finished at: Sun Jan 18 16:44:35 CET 2015
[INFO] Final Memory: 11M/205M
[INFO] ------------------------------------------------------------------------

Tutorial Sources

Please feel free to download the tutorial sources from my Bitbucket repository, fork it there or clone it using Git:

git clone https://bitbucket.org/hascode/jmeter-multiuser-profiling.git

Resources

Alternative: Gatling

I have written a tutorial  about another tool for writing load tests – please feel free to have a look: “Load Testing Web Applications with Gatling and Maven“.

    Article Updates

    • 2016-05-06: Link to Gatling tutorial added.
    • 2015-03-03: Added example assertion to verify the JSON response and a to verify the duration of the login process (thx @Wade Xu for the remark) .

    Tags: , , , , , , , , , , , ,

    2 Responses to “Performance Testing a Multiuser Web Application with JMeter and Maven”

    1. Wade Xu Says:

      How do you know the performance testing is passed, I mean is there assertion in the jmeter script?

    2. micha kops Says:

      Hi,

      you’re right, it might be useful to demonstrate adding some assertions to the test, thanks for your remark :)

      I’ll be adding an update with some example assertions, soon.

    Search
    Categories