Testing a web application with JMeter is easy, but when your application uses AJAX (with DWR, for instance) and sessions, it can be a complex task.
I’ve developed an application with DWR and i want to test the performance. DWR is one of the coolest project to make an AJAX applications, IMHO.
The first aproach with JMeter is to save a set of requests to reproduce later, but those requests are asociated with a session. So, if i run concurrently those requests in several threads:
- i don’t test what i want. I want one session per thread
- maybe i obtain inconsistent data
To record a set of request, we have to:
- In Test Plan add a Config Element/HTTP Request Defaults
- In HTTP Request Defaults set a value to Server Name or IP, Port Number and Protocol
This is necesary to chage easily the host and port of all request. If you don’t use a HTTP Request Defaults, every request recorded will have a host and port value, and if you want to test another host you have to chane a lot of values.
- In Test Plan add a Thread Group
- In this Thread Group add a Logic Controler/Recording Controller
It is a simple container for the requests.
- In WorkBench add a Non-Test Elements/HTTP Proxy Server
- In HTTP Proxy Server set Port, Target Controller and Pattern to Include
- In HTTP Proxy Server add a Timer/Gaussian Random Timer
- In the Gaussian Timer, set the Constant Delay Offset to ${T}
This record the time between every request with a random deviation. It’s very important to try to reproduce the user experience.
view JMeter screencast
In this screencast i introduced HTTP Cookie Manager and a listener item that didn’t be included in the above explanation. It will be used in stress time to let JMeter manage cookies to store JSESSIONID value of every thread (synthetic user) and view the results.
Now, it’s time to deploy your application and configure your browser to use the JMeter proxy.
view proxy screencast
Easy, isn’t it?
Try 1
Then, my next step was recording several users and grow up the JMeter config file. I’ve created several thread groups, one per concurrent user with distinct session IDs (remember to close the browser between every recording to clean cookies). But .., with six or seven users the files was almost 6 MB, it may vary in your project and the complexity of the user requests.
JMeter is a really cool application, but with this kind of file sizes, it needs a lot of memory. I’ve got a lot of OutOfMemoryExceptions and decided to record every new user from scratch to later merge in only one project file.
This was not a success experience, i only could get less than ten users and, the JMeter can’t use those big files, and i wasted a lot of time recording every new user, so …
Try 2
Regenerate a new session ID per thread. This seems to be easy, i have a lot of experience with xpath, and i can extract a portion of a html with it. First i created a .jsp to print the session ID:
<html>
<body>
<sessionid><%=session.getId()%></sessionid>
</body>
</html>
At the beginning of the user recording, i request this .jsp, and the i attach a Post Processor/XPath Extractor in this HTTP Request, with this values:
- Reference Name: USERSESSIONID
- XPath query: /html/body/sessionid/text()
Now i only have to replace the session IDs ocurrences in the JMeter config file (.jmx) with:
${USERSESSIONID}
I used jEdit to replace, only have to find the ID like E4B1B20074F2106ED330B98387EAF8E5 and replace all with the above text.
But … DWR needs another sessionid (script session id) and the JMeter failed
Try 3
I thought i could get DWR script session id like the session id, but minutes ago of reading the DWR code, i discover that engine.js have this values in JavaScript variables. Instead using XPath extractor y used a Regular Expresion extractor.
In the engine.js HTTP Request, attach two Regular Expresion Post Processor with:
- Reference Name: HTTPSESSIONID
- Regular Expression: DWREngine._httpSessionId = “(.*)”;
- Template: $1$
- Reference Name: SCRIPTSESSIONID
- Regular Expression: DWREngine._scriptSessionId = “(.*)”;
- Template: $1$

Then you have to replace the values like Try 2 in the DWR requests:
[...]
<stringProp name="Argument.value">1
httpSessionId=${HTTPSESSIONID}
scriptSessionId=${SCRIPTSESSIONID}
page=/smartcv2/Edit.do
c0-scriptName=MainForm
c0-methodName=setValue
c0-id=5943_1159885700394
c0-param0=string:biologicalDescriptors.dateOfBirth
c0-param1=string:October%2015%2C%201979</stringProp>
[...]
Check the .jmx file twice before loading in JMeter and if you have problems, use a TCP Monitor to see the HTTP traffic. Axis and Eclipse + WTP come with one (also netbeans, but i’ve not used yet).
See here the addendum for DWR 2.0RC2