SOAP/REST API Testing Using SoapUI
Created by Kavan Sheth
Best viewed in Chrome, Firefox, Opera or A browser supporting HTML5.
Use arrow keys ( up ↑, down ↓, left ←, right ↑) to navigate. Uses Reveal.js by Hakim El Hattab
Press ESC to enter the slide overview.
Once you open SoapUI, you will see something as below:
Create a new SOAP Project
Here we need two things, 1. Project Name and 2. WSDL
As you must be aware, SOAP services provides interfacing details using WSDL(Web Service Description Language). So you will need a WSDL specifying WebService to be tested.
Once you create project, you will get Auto Generated Dummy Request as following:
A Valid request for my createToken API is something like following:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns2="http://soap.crmapi.util.redknee.com/PaymentGatewayIntegration/xsd/2012/03"
xmlns:pay="http://soap.crmapi.util.redknee.com/PaymentGatewayIntegration/xsd/PaymentGatewayIntegration-v1.0"
xmlns:ns1="http://soap.crmapi.util.redknee.com/common/xsd/2008/08"
xmlns:ns="http://soap.crmapi.util.redknee.com/common/xsd/2011/05">
<soapenv:Header>
</soapenv:Header>
<soapenv:Body>
<pay:createToken>
<pay:header>
<ns:password>rkadm</ns:password>
<ns:username>rkadm</ns:username>
</pay:header>
<pay:request>
<ns2:accountID>19231123344</ns2:accountID>
<ns2:tokenValue>208</ns2:tokenValue>
<ns2:maskedCardNumber>3434324324325327</ns2:maskedCardNumber>
<ns2:expiryDate>201512</ns2:expiryDate>
</pay:request>
</pay:createToken>
</soapenv:Body>
</soapenv:Envelope>
So lets see what we are getting on sending this request.
On Sending request I am getting following response in SOAP Response Window:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Server</faultcode>
<faultstring>WSDoAllReceiver: Incoming message does not contain required Security header</faultstring>
<detail>
<Exception>org.apache.axis2.AxisFault: WSDoAllReceiver: Incoming message does not contain required Security header
at org.apache.rampart.handler.WSDoAllReceiver.processBasic(WSDoAllReceiver.java:221)
...<Truncated Exception Detail>
at java.lang.Thread.run(Thread.java:662)</Exception>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
Whenever there is some issue Soap server sends a response with faultcode and faultstring. Here it says "Incoming message does not contain required Security header". So here some security headers are expected by SOAP server in soap request. In My case it is username and timestamp token, which are missing, Let's see how to add these tokens to your security header.
Double click on your project e.g.
It will open Project Property Window, Select WS-Security Configurations Tab, on this tab select Outgoing WS-Security Configurations tab. It will look like this:
Add Token one by one as shown in below GIF:
Something like as shown in below GIF:
Sending REST request is simple and similar to SOAP request
I will be using following Request and URL(It is based on an internal project so data is irrelevant here)
URL:http://optimus-z2:11100/AppCrmInvoice/home?cmd=UsageStatementCharge
Method:POST
<request version="1.0">
<agentID>rkadm</agentID>
<requestID>1234567890</requestID>
<header>
<name>username</name>
<value>test</value>
</header>
<header>
<name>securityToken</name>
<value>test</value>
</header>
<parameter>
<name>subscriberId</name>
<value>12100765-1</value>
</parameter>
<parameter>
<name>spid</name>
<value>1</value>
</parameter>
<parameter>
<name>usageCriteria</name>
<value>1|1|0|Local Call|1</value>
</parameter>
<parameter>
<name>invoiceId</name>
<value>TAXSEQID802</value>
</parameter>
<parameter>
<name>language</name>
<value>en</value>
</parameter>
<parameter>
<name>interfaceId</name>
<value>WSC</value>
</parameter>
</request>
Similar to SOAP, create a new REST Project, you can provide either URL or WADL(Web Application Definition Language, like WSDL).
You can also use RESTClient, a FireFox Extension, to send REST Requests.
What usually a TestCase requires?
SoapUI and SoupUI NG Pro(yes, sorry to say paid version) provides these functionality to design your test cases.
If you have enough resources, it is always beneficial to go with Pro.
If you are in other category(not so resourceful) and a bit techie, you can do most of the things using SoapUI free version.
To start with, right click on project and create TestSuit, now right click on TestSuite and create a TestCase. Right click on TestCase and click on "Add Step". Following are steps in SoapUI Free and in Pro version:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sub="http://soap.crmapi.util.redknee.com/subscriptions/xsd/Subscriptions-v2.0" xmlns:ns="http://soap.crmapi.util.redknee.com/common/xsd/2011/05" xmlns:ns1="http://soap.crmapi.util.redknee.com/common/xsd/2008/08" xmlns:ns2="http://soap.crmapi.util.redknee.com/subscriptions/xsd/2011/01">
<soapenv:Header/>
<soapenv:Body>
<sub:getSubscriptionBalance>
<sub:header>
<ns:password>ltups30</ns:password>
<ns:username>rkadm</ns:username>
</sub:header>
<sub:subscriptionRef>
<ns2:accountID>${#TestCase#ban}</ns2:accountID>
<ns2:identifier>${#TestCase#ban}-1</ns2:identifier>
<ns2:spid>1</ns2:spid>
<ns2:subscriptionType>10001</ns2:subscriptionType>
<ns2:state>1</ns2:state>
</sub:subscriptionRef>
</sub:getSubscriptionBalance>
</soapenv:Body>
</soapenv:Envelope>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns14:getSubscriptionBalanceResponse xmlns:ns14="http://soap.crmapi.util.redknee.com/subscriptions/xsd/Subscriptions-v1.2">
<ns14:return>
<ns10:amount xmlns:ns10="http://soap.crmapi.util.redknee.com/subscriptions/xsd/2010/06">0</ns10:amount>
<ns10:expiryDate xmlns:ns10="http://soap.crmapi.util.redknee.com/subscriptions/xsd/2010/06">2015-06-07T00:00:00.000-04:00</ns10:expiryDate>
<ns10:givenMobileNumber xmlns:ns10="http://soap.crmapi.util.redknee.com/subscriptions/xsd/2010/06">7700085225</ns10:givenMobileNumber>
<ns10:primaryMobileNumber xmlns:ns10="http://soap.crmapi.util.redknee.com/subscriptions/xsd/2010/06">7700085225</ns10:primaryMobileNumber>
<ns10:currency xmlns:ns10="http://soap.crmapi.util.redknee.com/subscriptions/xsd/2010/06">CAD</ns10:currency>
<ns10:blockedBalance xmlns:ns10="http://soap.crmapi.util.redknee.com/subscriptions/xsd/2010/06">0</ns10:blockedBalance>
</ns14:return>
</ns14:getSubscriptionBalanceResponse>
</soapenv:Body>
</soapenv:Envelope>
and target is to store expiryDate from response in a property to use it later.
def param1 = testRunner.testCase.getPropertyValue( "param1" )
def param1 = context.testCase.testSuite.getPropertyValue( "param1" )
def param1 = testRunner.testCase.testSuite.project.getPropertyValue( "param1" )
Or
def param1 = context.expand('${#Project#param1}')
def param1 = context.expand('${#TestCase#param1}')
def param1 = context.expand('${#TestSuite#param1}')
context.testCase.setPropertyValue( "param1","xyz" )
context.testCase.testSuite.setPropertyValue( "param1","xyz" )
context.testCase.testSuite.project.setPropertyValue( "param1","xyz" )
def myTestCase = context.testCase
int x = Math.random()*100000 + 93000000
myTestCase.setPropertyValue("ban", x.toString())
log.info context.expand('${#TestCase#ban}')
Here I will not go into details of each Data Source, because it is trivial to use any data source and it is always good to know what can be done, how to do can be figured out on need to know basis.
As you can see, SoapUI NG Pro supports almost all possible datasource configurations, using them is too easy. Don't loose heart, SoapUI free provides groovy script and many thing can be achieved using groovy scripts, so here I will list out how to accomplish same datasource configurations using Groovy.
import groovy.sql.Sql
//Need to register driver first
//for SQL Server use: com.microsoft.sqlserver.jdbc.SQLServerDriver
//for MySQL: com.mysql.jdbc.Driver
com.eviware.soapui.support.GroovyUtils.registerJdbcDriver("oracle.jdbc.driver.OracleDriver")
con = Sql.newInstance("jdbc:oracle:thin:@DBHost:1521:DBName", "DBUser", "DBPasword")
def res = con.rows("SELECT sysdate FROM dual")
log.info(res[0].sysdate.toString())
con.close()
Note: Any external jar that should be added to SoapUI classpath, needs to be added in bin/ext folder(In this case ojdbc6.jar).
//reading all txt file at once
File file = new File("D://user.txt")
fileContent = file.getText()
log.info fileContent
//reading text line by line
File file1 = new File("D://user.txt")
List textLine = file1.readLines()
log.info textLine
//reading one line at a time
context.fileReader = new BufferedReader(new FileReader("C:\\PerTableData\\TestData.csv"))
//Read in the first line of the data file
nextLine = context.fileReader.readLine()
while(nextLine != null){
nextLine = context.fileReader.readLine()
log.info nextLine
}
import jxl.*
import jxl.write.*
Workbook workbook1 = Workbook.getWorkbook(new File("c:\\some.xls"))
Sheet sheet1 = workbook1.getSheet(0)
Cell a1 = sheet1.getCell(0,2) // getCell(row,column) -- place some values in myfile.xls
Cell b2 = sheet1.getCell(2,2) // then those values will be acessed using a1, b2 & c3 Cell.
Cell c2 = sheet1.getCell(2,1)
log.info a1.getContents()
log.info b2.getContents()
log.info c2.getContents()
workbook1.close()
Note: Need to place jxl.jar under bin/ext folder, jxl works with xls only and not with .xlsx, You can use Apache POI if want to read .xlsx
Consider an xml with multiple Employee tags, each Employee tag have age and name as sub elements. Following script will print name of each Employee having age > 19.
//Read and parse XML file and store it into a variable
def InputXML = new XmlParser().parseText(inputFile.text)
//Find - Filter XML nodes based on a condition
def InputRow = InputXML.Employee.findAll{
it.Age.text().toInteger() > 19;
//We are finding all XML nodes where the age > 19
}
InputRow.each{
//Display the value of name node from the filtered record
log.info(it.Name.text());
}
So Similarly you can try/find for other dataSources. Main point is Groovy Script Rocks :).
Another important step in SoapUI NG Pro is DataSource loop.
Data read from DataSources represents different possible input to a TestCase, so we need to run TestCase with each of the data retrieved and for that we need to create loop to instantiate our TestCase with different data set.
Found a good article here.
We need three steps here:
Any of your repetitive TestSteps should go between DataSource and DataLoop
Here we need to define three properties. with Empty values.
count - counter used for looping
value - contains value from dataSource(here value from a file). you can add as many properties as you want.
stoploop - a string used in DataLoop Step to determine whether to stop or move back to initial step
def myTestCase = context.testCase
def counter,size,stoploop,tempValue
//make sure input.txt file already exists and
//contains different set of values separated by new line (CR).
File fileData = new File("c://redknee/input.txt")
List lines = fileData.readLines()
size = lines.size.toInteger()
//Read Properties and Initialize if first iteration
propTestStep = myTestCase.getTestStepByName("Property-Looper")
cnt=propTestStep.getPropertyValue("count")
counter=(cnt==""? 1: cnt.toInteger() )
stoploop="F"
//loop condition
if(counter<=size)
{
tempValue = lines[counter-1]
log.info tempValue
if (counter == size)
stoploop="T"
counter=counter+1;
}
//update property values
propTestStep.setPropertyValue("value", tempValue.toString())
propTestStep.setPropertyValue("count", counter.toString() )
propTestStep.setPropertyValue("stoploop", stoploop.toString())
def myTestCase = context.testCase
propTestStep = myTestCase.getTestStepByName("Property-Looper")
endLoop = propTestStep.getPropertyValue("stoploop").toString()
if (endLoop.toString() == "T")
{
log.info ("Exit Groovy Data Source Looper")
propTestStep.setPropertyValue("value", "")
propTestStep.setPropertyValue("count", "")
propTestStep.setPropertyValue("stoploop", "")
assert true
}
else
testRunner.gotoStepByName("GroovyScript-DataSource") //setStartStep
So using groovy most of the things can be achieved, just need to look around.
Good thing about SoupUI is, there is almost no overhead for load test once you have your TestCase ready.
Main thing about load testing is the strategy for Load.
As you can see in image, here loadTest is run for 5 threads, with "Simple" Strategy, TestDelay 1000, TotalRuns limit 10.
Following image may help you understand the load patterns:
Load Test Assertions are very important feature. Using LoadTest Assertions you can fail your Load test if it is not meeting some criteria, like avg time for a particular step exceeds permissible limit.
Once done with setup, you can run your load test as following:
sh SoapUI-5.1.3/bin/loadtestrunner.sh
-s"TestSuite Name"
-c"TestCase Name"
-l"LoadTest Name"
-r
-f/path/for/reports/
loadtest-soapui-project.xml
Once LoadTest is over, you will find load test statistics and error logs under path provided with -f argument.
$ cat LoadTest_1-log.txt
time,type,step,message
2015-05-21 23:54:51,Message,,"LoadTest started at Thu May 21 23:54:51 IST 2015"
2015-05-21 23:55:32,Message,,"LoadTest ended at Thu May 21 23:55:32 IST 2015"
$ cat LoadTest_1-statistics.txt
Test Step,min,max,avg,last,cnt,tps,bytes,bps,err,rat
banSelection,1,128,0.93,0,160,3.83,0,0,0,0
getSubscriptionBalance - Request 1,436,2699,528.77,490,160,3.83,174720,4188,0,0
TestCase:,437,2827,529.7,490,160,3.83,174720,4188,0,0
$