Multithreaded load testing with soapUI

By Michael Young - Snack Overflow
Last updated: 19.09.2017
soapUI SOAP Web Services Groovy load testing

Introduction

To realistically load test our vehicle data webservice we wanted to replay actual requests made by customers to our test environment. So from our production log files we extracted the request type, the product codes and the vehicle registration marque into a CSV file. This file was then used as a data source for our load test.

A simple load test in soapUI can be created with minimal effort. To replay requests in a sequence in a multi-threaded load test requires a synchronized data feed. This can be achieved by using Groovy code steps in the test case. The code samples in this article will show you how to do this in a thread safe manner.

The screenshot shows the layout of the project, the Groovy code test steps are indicated by blue stars.

Synchronized Data Feed

The first step initialise LoadTest contains the class definition for the data feed and safe instantiation of the data feed object.

import groovy.transform.Synchronized
class SyncDataFeed {
	static def BufferedReader dataReader=null
	static def int vrmCount=0
	static def PrintWriter report=null
	static def int maxReads=0
	static def reportEnabled=false
	
	SyncDataFeed(String filename, String reportFile,int count, boolean enableReport){		
		maxReads=count
		dataReader = new BufferedReader(new FileReader(filename))
		reportEnabled=enableReport
		if(reportEnabled)
		{
			report= new PrintWriter(reportFile)		
			report.println("Setup Data Coverage Test using input file "+filename)
			report.flush()			
		}				
	}

	@Synchronized
	def getNextLine(){
		vrmCount++
		if(vrmCount>maxReads)
		{
			return null		
		}
		else
		{
			def inputText= dataReader.readLine()
			Date now=new Date()
			if(reportEnabled)
			{
				report.println(now.toString()+" "+Thread.currentThread().name+" "+inputText)
				report.flush()				
			}
			return inputText			
		}
	}

}
 
Now to create an instance of the class we first check to see if we are running as a multi threaded load test using the object context.LoadTestContext
if(context.LoadTestContext!=null)
{
	synchronized( context.LoadTestContext )
	{
		if(context.LoadTestContext['syncFeed']==null)
		{
			context.LoadTestContext['syncFeed']=new SyncDataFeed("/LoadTest/data/load_test_enquiries.csv","/soapUILogs/report.log",2000000,true)
		}
	}
}
else
{
	log.info("do nothing for single threaded TestCase run")
}

 

Reading the data and populating the SOAP request

The next step readInputFile will use the syncFeed object to read from the input file

def inputText=null

if(context.LoadTestContext!=null)
{
	inputText=context.LoadTestContext['syncFeed'].nextLine
}
else
{
	//single threaded
	inputText=context["dataFeed"].nextLine
}

 

inputText contains the a single line of comma separated values to be used in the request. Using a string tokenizer these are put in separate variables.

	def tok= new java.util.StringTokenizer(inputText.trim(),",")
	def enquiryType=tok.nextToken()
	def customerCode=tok.nextToken()
	def vrmText=tok.nextToken()
	def primaryProduct=tok.nextToken()

 

These are then loaded into test case properties which can be used as parameter values in a SOAP request

e.g.

testRunner.testCase.setPropertyValue("primaryProduct",primaryProduct)

is then used in the XML body of a SOAP request

<Code>${#TestCase#primaryProduct}</Code>

 Selecting which SOAP request to make is a simple test then a goto 

if(enquiryType.equals("core"))
{		
     testRunner.gotoStepByName("prepareCore")
}

 

From the prepareCore step we move onto making the CoreRequest. Within the request step we add some basic assertions to check it responded correctly within a certain time period. The coreDone step simply loops back to the readInputFile step. The test continues with the next line from the input file which populates the next request in the sequence. In a load test this will all be done in parallel by multiple threads.

Running the Load Test

We can run TestCase1 in a single thread to prove it works but what we really want to do is run multi threaded LoadTest1. The soapUI LoadTest window gives many options such as how many threads to use, what strategy and for how long. When the test is complete it gives stats on what happened. In practice we ramped up the loading to see what volume of requests the service could cope with and still return responses within an acceptable time.

Conclusion

To develop a thread safe load test create your own data feed class with synchronized methods that read from a source file or database. Use the context.LoadTestContext object to store the instance of this data feed and to determine if you are in "load test" mode. Populate your soap requests with values taken from the data feed using test case properties. Then run the load test multiple times increasing the number of threads until you see your system performance drop below an acceptable level.

This approach can also be used with JSON based Restful services. The same Groovy code can be used and the test case properties can be used as parameters within the Restful requests.