The Holy Java

Building the right thing, building it right, fast

Webservice testing with JMeter: Passing data from a response to another request

Posted by Jakub Holý on June 4, 2010

JMeter is great for functional and performance testing of many things, including web services (and to my surprise also LDAP). It also provides means for extracting data from a response and passing them to a subsequent request, which is exactly what I needed. There is already a good tutorial on testing a WS with JMeter, so I won’t repeat the basic setup here. The steps are:

  1. Create a webservice (WS) test plan, as described in the tutorial (in my case it contains two WS calls)
  2. Add the User Defined Variables config element to the test plan and define there a variable for transferring the response data
  3. Add an XPath Extractor Post Processor to the first WS call to extract the value of interest into the user defined variable (beware namespaces!)
  4. Add a BeanShell Pre Processor to the second call, which will replace a placeholder in the WS call’s XML data with the value of that variable

About the webservice

I needed to test a web service, which requires its client to call first its authenticate method, which returns an authentication token called ‘certificate’, which is then used in subsequent requests.

A basic implementation

0. Setup

Download JMeter 2.3.4 and two dependencies, Java Mail API (mail.jar) and JavaBeans Activation Framework (activation.jar), necessary for the JMeter’s webservice sampler. Put the JARs in JMeter’s lib/ folder.

1. Create a webservice (WS) test plan, as described in the tutorial (in my case it contains two WS calls)

Well, follow the utorial :-). Then duplicate the webservice call sampler, call the first one WS: Authenticate with Saba and the other one WS: PF – Update employees.

2. Add the User Defined Variables config element to the test plan and define there a variable for transferring the response data

We will need a variable to hold the data that we want to transfer from the 1st response to subsequent request. Therefore open the test plan, right-click on Thread Group > Add > Config Element > User Defined Variables. Add there  a variable named sabaCertificate. You can leave its Value empty.

3. Add an XPath Extractor Post Processor to the first WS call to extract the value of interest into the user defined variable

Now we will extract the “certificate” data from the first response. The response may look like this (I used Eclipse’ TCP Monitor to capture the SOAP communication):

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <soapenv:Body>
 	<saba:certificate xmlns:saba="http://www.saba.com/xml/infoservices">31323930326436636637635</saba:certificate>
 </soapenv:Body>
</soapenv:Envelope>

To extract the value of the element <saba:certificate>:

  1. Right-click on the first WS call (WS: Authenticate with Saba) and Add > Post Processors > XPath Extractor
  2. For the Reference Name, type sabaCertificate (the user variable we’ve created earlier)
  3. For the XPath query, type //*[local-name()='certificate']/text()
    • Problem with namespaces: Beware that JMeter 2.3.4 supports only namespaces declared on the root element and thus the XPath query //saba:certificate wouldn’t work. The documentation for XPath Extractor’s attribute “Use Namespace?” provides a workaround based on using the functions local-name() and namespace-uri() to match the local tag name and the URI associated with its namespace, which I’ve partly used.
    • You can test your XPath for example in the Allans Online XPath Tester

4. Add a BeanShell Pre Processor to the second call, which will replace a placeholder in the WS call’s XML data with the value of that variable

Now we need to get the “certificate” into the subsequent web service request. I have put the placeholder “#sabaCertificate#” into the SOPA request, at the place where the actual authentication token shall be. Now we will arrange for its replacement with the actual value:

  1. Right-click on the second WS call (WS: PF – Update employees) and Add > Pre Processors > BeanShell PreProcessor (BeanShell is a scripting language with Java syntax and is included in JMeter)
  2. Type in the following script (notice that sampler is a variable provided by JMeter and refers to the parent WS call; check JavaDoc for details on the WebServiceSampler):

Case 1: SOAP request specified directly in the attribute Soap/XML-RPC Data

import org.apache.jmeter.protocol.http.sampler.WebServiceSampler;
WebServiceSampler wsSampler = (WebServiceSampler) sampler;
String requestWithCertif = wsSampler.getXmlData().replaceFirst("#sabaCertificate#", vars.get("sabaCertificate"));
wsSampler.setXmlData(requestWithCertif);

Case 2: The SOAP request is read from a file (attribute File with SOAP XML Data)

If the request data is read from a file then it’s a bit more complex because we need to load its content.

import org.apache.jmeter.protocol.http.sampler.WebServiceSampler;
import java.io.*;

WebServiceSampler wsSampler = (WebServiceSampler) sampler;

BufferedReader xmlReader = new BufferedReader( new InputStreamReader(
	new FileInputStream(wsSampler.getXmlFile())
	, java.nio.charset.Charset.forName("UTF-8")
));

StringBuffer xmlData = new StringBuffer();

String line;
while( (line = xmlReader.readLine()) != null) { xmlData.append(line).append('\n'); }

String requestWithCertif = xmlData.toString().replaceFirst("#sabaCertificate#", vars.get("sabaCertificate"));

wsSampler.setXmlData(requestWithCertif);
wsSampler.setXmlFile("") ; // a file would override the data

// print("XML set: " + requestWithCertif); // print to the console JMeter was started from

Well, that’s it!

Going advanced: Reading requests from several files

The approach descibed above makes it possible to send a request based on a single file. But what if we want to send a different data with each repetition of the test, e.g. to negate effects of caching? Well, there is a couple of ways to achieve that. I’ve chosen the most flexible one, though absolutely not the easiest one to implement.

The trick is:

  1. Create a BeanShell Sampler. The sampler will list all files in a particular directory and store their paths into a numbered variables (G_updateEmployeesWsRequestFile_1 etc., must start with 1), which will be then used by a ForEach Controller.
  2. Put all the test elements from the basic test plan under a ForEach Controller , which follows the BeanShell Sampler. Configure it to use the variables generated by the BeanShell Sampler and store the current file name in the variable G_updateEmployeesWsRequestFile.
  3. In the webservice request element, replace the content of the Filename field with a reference to that variable: ${G_updateEmployeesWsRequestFile}

The BeanShell Sampler “Generate WS request file names

import java.io.*;

print("Generating files...");
log.info("BeanShell Sampler: Generating request file names...");

File requestsDir = new File("/tmp/wsRequests");
String[] requestFiles = requestsDir.list();

for(int i=0; i<requestFiles.length; ++i) {
	String varName = "G_updateEmployeesWsRequestFile_" + (i+1);
	vars.put(
		varName
		, requestsDir.getAbsolutePath()  + File.separatorChar  + requestFiles[i]
	);
	// print("var created: " + varName + "=" + vars.get(varName));
}

log.info("BeanShell Sampler: FINISHED generating request file names from dir " +
	requestsDir + "; files are: " + java.util.Arrays.asList(requestFiles));

return "soap input files generated";

The ForEach Controller “ForEach request file

The controller’s configuration is simple:

  • Input variable prefix: G_updateEmployeesWsRequestFile
  • Output variable name: G_updateEmployeesWsRequestFile
  • Add “_” before before number: [x] (checked)

Summary

We’ve parametrized the test by a set of files with SOAP requests that are read from a folder and supplied sequentially to the test thanks to the ForEach Controller.

Resources

About these ads

10 Responses to “Webservice testing with JMeter: Passing data from a response to another request”

  1. javabean said

    Interesting article, Jakub. How does your JMeter setup compare to Soapui ?

  2. Stan said

    SOAPui is a bit more userfirendly has similar capabilites as jmeter.
    If you need a smoke test tool it is even better in my opinion.
    But in advanced options jmeter seems to be more usefull since you can inject code in Beanshell and do some manipulation on data.

  3. [...] Webservice testing with JMeter: Passing data from a response to another request (tags: jmeter webservices) [...]

  4. Srini said

    I have tried above mentioned steps and still unable to capture a value from the response and pass to another webservice request.

    Here is the Sample Response tag :-

    85579758

    I need to pass above securityCode value to another threadgroup web serivce request. Can you please provide me the information would be much appreciated.

    • Sorry Srini, I don’t know anything more than written above (certainly not now, over one year later). Good luck!

    • jon said

      Helpful, thanks. One tidbit: in the sample, there is a typo ‘XMLSamper’ instead of ‘XMLSampler’ for the node that contains the java code to get the response.

  5. tanu said

    hi

    I want to use Jmeter for our webservices performance testing. Following are

    the configurations we are using:
    WSDL 1.0, Axis 2, Soap 1.1 and jmeter v 2.7

    My webservice URL is
    http://mail.cryoserver.com:8080/cryoapi/services/cryoservice?wsdl

    But when I try to load this webservice viz jmeter it is not responding, Could

    you plz tell me what is wrong with this webservice.

    • Hi Tanu,

      no, sorry, I cannot help you. Try curl, check the logs, in the worst case use Wireshark. Make sure the URL is correct (the ?wsdl at the end looks suspicious).

Sorry, the comment form is closed at this time.

 
%d bloggers like this: