Testing Webservice with JMeter: Passing data from one response to another request
💻 coding

Testing Webservice with JMeter: Passing data from one response to another request

5 min read 1,073 words
5 min read
ShareWhatsAppPost on X
  • 1JMeter is effective for testing web services by allowing data extraction from responses for use in subsequent requests.
  • 2To pass data between requests, create a User Defined Variables element and an XPath Extractor Post Processor in JMeter.
  • 3The authentication token, 'certificate', is extracted from the first web service call to be used in later requests.

AI-generated summary · May not capture all nuances

Key Insight
AskGif

"JMeter is effective for testing web services by allowing data extraction from responses for use in subsequent requests."

Testing Webservice with JMeter: Passing data from one response to another request

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.

The steps are:

Create a web service (WS) test plan, as described in the tutorial (in my case it contains two WS calls)

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

Add an XPath Extractor Post Processor to the first WS call to extract the value of interest into the user-defined variable (beware namespaces!)

Add a BeanShell PreProcessor to the second call, which will replace a placeholder in the WS call's XML data with the value of that variable

About the web service

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 web service sampler. Put the JARs in JMeter's lib/ folder.

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

Well, follow the tutorial :-). Then duplicate the web service 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 a 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>:

Right-click on the first WS call (WS: Authenticate with Saba) and Add > Post Processors > XPath Extractor

For the Reference Name, type sabaCertificate (the user variable we've created earlier)

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

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)

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

Create a BeanShell Sampler. The sampler will list all files in a particular directory and store their paths into numbered variables (G_updateEmployeesWsRequestFile_1 etc., must start with 1), which will be then used by a ForEach Controller.

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.

In the web service 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.

Enjoyed this article?

Share it with someone who'd find it useful.

ShareWhatsAppPost on X

AskGif

Published on 25 June 2019 · 5 min read · 1,073 words

Part of AskGif Blog · coding

You might also like