Posted by SmartBear on Thursday, September 15, 2011

Customer Guest Blog
Pradeep Bishnoi, Quality Analyst (API Test Automation), Thomson Reuters, Bangalore

A few days back, in one of my recent blog posts published on learnsoapui.wordpress.com, I shared the simplest way to perform load testing using the soapUI tool. I was happy performing the API load test using soapUI/loadUI until the day one of my colleagues asked me about my approach for performing these tests. I happily shared the information and in response he got me  thinking by asking a very genuine question [and a flaw in the approach] about the approach being used to perform the load test.

"Are my tests parameterized? If not, then this is not the actual load test scenario since the DB is returning the data from the cache for each new request."

After this question, I realized that my approach to perform these API load tests is wrong :( so I started seriously thinking along the same lines and the answer to this problem was not far from my reach. ;-) Now you might have already started thinking, "What if I parameterize my request input and perform the load test instead of using a static request? Would this solve the problem?" Well not completely. How?

As you know, the web service request can be parameterized from xls, txt or any other source and the response would vary as per the input. I was using a simple TXT as the source with a script reading the input values, storing them as a custom property and passing the property value with each request run. Now having this approach, the only drawback is that when you perform the load test, the script will reach EOF (end of file) and the custom property will contain that (last value) as input value. Now this value would be passed as the input parameter for each request run during my load test and resulting in an INVALID load test scenario.

I have used profiler and HTTP data packet monitoring tools to verify the request data being sent from my local machine to Webserver and found it is sending the same request data multiple times during the load test.

How do you deal with this limitation/challenge with the soapUI tool? I searched a lot on the Internet, however with no success. Then I started analyzing the other load testing tools available in the market for performing such tests and found HP LoadRunner as one of the completive tools to achieve this.

Being a gigantic fan of open source tools like soapUI, loadUI and Groovy, I was not overly excited about introducing another load testing tool such as LoadRunner (another hefty licensed software). However, the feature it provided (randomly passing input parameter) was one that was attractive to me because by using that it was just matter of a few clicks to simulate actual load test scenario.

However, if I did introduce another load testing tool for the job, I would have to do a lot of extra stuff, and it was like an extra "load," in and of itself, such as if I created the new load test in LoadRunner, had to select individual request data and parameterize the input and provide a list of input values and so on. 

This headache was avoided by using the existing soapUI tool, with an already created parameterized input request and an input TXT file.

As I have mentioned many times before (in my blog and to other people) you can do "wonders with Groovy" and "almost everything can be achieved with Groovy in soapUI." So going by those words, I wrote a couple of Groovy code lines to achieve what I was looking for - "Parameterized load testing".

The approach is no different from what "load runner" is actually using and also the way our parameterized test works. The only difference is, now it will randomly read an input value from the list (in my case a TXT file) and set it to custom property instead of reading in a sequence (which leads us to End Of File and resulting into static input data). Let everything remain the same - your parameterized test request, all test steps, and the file from where you read input values. And just add one new Groovy test step (in your testcase) and a new custom property “inputValue” at testcase level.

/*
@Author : Pradeep Bishnoi
@Description : Randomly read the input value from the input file. Each input value is entered in a new line. So, my file now contains 11 lines/input values.
*/
def myTestCase = context.testCase

File tempFile = new File("d:/my_Input_File.txt")
List lines = tempFile.readLines()

def x = Math.random()*10       // multiplying random with 10 so the resulting value would be <= 10.
i = String.valueOf(x).getAt(0)
i = i.toInteger()
myTestCase.setPropertyValue("inputValue", lines[i])
inputValue = context.expand( '${#TestCase#inputValue}' )
log.info inputValue

On running the load test each virtual user (thread) will also call this script teststep – because this teststep belongs to the same testcase (or group of my parameterized test steps). And with every run of this test step my custom property value would be updated resulting in request data with a different input value. This can be verified using a profiler or HTTP monitoring tool. Mission accomplished :) Leave your comments and thoughts and don’t forget to visit my blog at http:// learsoapui.wordpress.com. Till next blog - Happy reading and sharing!!

Snapshot for ready reference, how it will look after adding this Groovy teststep:

Parameterized Load Testing Using soapUI

 

Note : In soapUI Pro you can use Data Source, etc. instead of scripting.

Share this blog post:
  • Facebook
  • DZone It!
  • Digg It!
  • Del.icio.us
  • Reddit
  • Twitter
  • Email It!

Comments  20

Gravatar
  • Alexander 09/23/2011 12:43 PM

    Thanks for this post, very useful. But what if I want to use it for bigger number of parameters, e.g. from 1 to 999?

    Simply changing the code to this one:

    def x = Math.random()*1000   
    didn't help...

    Could you please advise?
    Thanks in advance.

     
    Gravatar
  • Pradeep Bishnoi 09/27/2011 06:34 AM

    Well, it should work. This is what i received on using math.random()*1000

     Tue Sep 27 15:57:25 GMT+05:30 2011:INFO:771.2958701912469
    Tue Sep 27 15:57:25 GMT+05:30 2011:INFO:409.59005739872345
    Tue Sep 27 15:57:26 GMT+05:30 2011:INFO:937.6728813244142
    Tue Sep 27 15:57:28 GMT+05:30 2011:INFO:672.5041982429649
    Tue Sep 27 15:57:28 GMT+05:30 2011:INFO:604.6272631878885
    Tue Sep 27 15:57:29 GMT+05:30 2011:INFO:999.8832310319019
    Tue Sep 27 15:57:29 GMT+05:30 2011:INFO:741.7095620279971
    Tue Sep 27 15:57:29 GMT+05:30 2011:INFO:954.186877584236
    Tue Sep 27 15:57:30 GMT+05:30 2011:INFO:142.97478100597348
    Tue Sep 27 15:57:30 GMT+05:30 2011:INFO:252.71233730991915
    Tue Sep 27 15:57:31 GMT+05:30 2011:INFO:730.4790990649641
    Tue Sep 27 15:57:31 GMT+05:30 2011:INFO:475.0529351883561
    Tue Sep 27 15:57:32 GMT+05:30 2011:INFO:242.2475236548165
    Tue Sep 27 15:57:32 GMT+05:30 2011:INFO:104.24179377799625
    Tue Sep 27 15:57:33 GMT+05:30 2011:INFO:659.5052035325352
    Tue Sep 27 15:57:33 GMT+05:30 2011:INFO:924.4814583202465
    Tue Sep 27 15:57:34 GMT+05:30 2011:INFO:903.8572676172342
    Tue Sep 27 15:57:34 GMT+05:30 2011:INFO:550.2099940519724
    Tue Sep 27 15:57:35 GMT+05:30 2011:INFO:15.693317517185502
    Tue Sep 27 15:57:36 GMT+05:30 2011:INFO:637.8244404241224

    and it covers all the values in between that range.
    I guess you might be missing out on something :-)

    regards,
    /pradeep bishnoi

     
    Gravatar
  • Alexander 09/28/2011 04:41 AM

    Thanks for your reply.
    Yes, the simple expression def x = Math.random()*1000 works. But the full one

    def myTestCase = context.testCase

    File tempFile = new File("d:/my_Input_File.txt")
    List lines = tempFile.readLines()

    def x = Math.random()*1000       // multiplying random with 10 so the resulting value would be <= 1000.
    i = String.valueOf(x).getAt(0)
    i = i.toInteger()
    myTestCase.setPropertyValue("UserLogin", lines[i])
    inputValue = context.expand( '${#TestCase#UserLogin}' )
    log.info inputValue

    doesn't. It looks like this script fetches only the first 10 lines from the file but not 1000 as specified.

    NOTE: in a file I have a bunch or user emails and I want this script to randomly select an email for example to simulate a "rush" login operation.

    Thanks in advance.
    Alex

     
    Gravatar
  • Pradeep Bishnoi 09/29/2011 12:38 PM

    Hi Alex,

    Thanks for pointing this out. Actually the code written (in blog) is meant to get the first digit from the Random value generated. Below is the code line which is doing this.
    i = String.valueOf(x).getAt(0)


    So if you replace the above code line with this one..
    i = x.toInteger()

    then it would return the complete integer value which would be from the specified range (1-1000).

    Hope this will answer your concern.

    Best Regards,
    /Pradeep Bishnoi

     
    Gravatar
  • Mohd Asim Khan 09/30/2011 09:20 AM

    Hi Pradeep,

    Nice blog. I am new to web services.
    I need to do the same task but I dont know in which manner I mention the values in txt file.
    In my soap request there are 3 values in soap header and 6 (+1 is optional) values in soap body.
    Can you please explain me how the script file put the values in soap request form the text file.
    Thanks in advance.

    Mohd Asim Khan

     
    Gravatar
  • Pradeep Bishnoi 09/30/2011 11:31 AM

    Hi Asim,

    Thanks for your feedback.
    Well, to achieve the same you can create separate txt files for each input value. And then read the values of the same by updating (appending) the script & creating the new property to hold all different values. That would be more efforts when more the number of field.
    Or as an alternative, create an excel file and use each column as different parameter input.
    And to know "how to read an excel file" refer my learnsoapui.wordpress.com blog.

    Hope this will be pointer for you to proceed in the right direction.

    Thanks!
    /Pradeep Bishnoi

     
    Gravatar
  • Mohd Asim Khan 09/30/2011 12:30 PM

    Hi Pradeep.

    Thanks for quick response.
    But I am still not clear about this.
    I have following SOAP request for which I want parameterized load testing.

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://webservices.employee.com/">
       <soapenv:Header>
          <web:employeeId>
             <id>Emp01</id>
          </web:employeeId>
       </soapenv:Header>
       <soapenv:Body>
          <web:getEmployeeList>
             <!--Optional:-->
             <param>
                <name>Asim</name>
                <dept>Operations</dept>
                <joiningDate>2011-10-20</joiningDate>
             </param>
          </web:getEmployeeList>
       </soapenv:Body>
    </soapenv:Envelope>

    Can you please explain with this example.
    Thanks in Advance.

    Mohd Asim Khan

     
    Gravatar
  • Alex Forbes 09/30/2011 12:45 PM

    Hi Mohd,

    Also please feel free to post your question, with a link back to this blog post from Pradeep, in the soapUI forum (I include a link above).

    Thank you for your ongoing support Pradeep.

    Best,
    Alex
    SmartBear Community Manager

    http://twitter.com/alexnforbes

    http://twitter.com/soapUI
    http://www.linkedin.com/groups/Web-Service-Testing-loadUI-soapUI-4082922

    http://twitter.com/smartbear
    http://twitter.com/sqconnection

    http://www.facebook.com/smartbear
    http://www.facebook.com/softwarequalityconnection

    http://www.linkedin.com/company/smartbear-software

     
    Gravatar
  • Zee 10/16/2011 23:32 PM

    Hi Mohd Asim Khan,

    Did you recieve an answer to your last question?

    Can you please tell us what did you change in you XML file to read from the Groovy Script?

    Thanks
    Zee

     
    Gravatar
  • Zee 10/17/2011 08:23 AM

    Hi Pradeep Bishnoi,

    Thanks for the article mate. It really works well.

     
    Gravatar
  • Zee 12/16/2011 14:56 PM

    Hello Mohd Asim Khan and Zee,


    Did you get an answer to your question? Can you please post here if you did.

    Regards,

    Zee

     
    Gravatar
  • Pradeep Bishnoi 12/17/2011 08:17 AM

    Hi Zee & Asim,

    As per the request data posted in above comments, we have to modify the same slightly.  Modified version would look like this :

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://webservices.employee.com/">
       <soapenv:Header>
          <web:employeeId>
             <id>${TestCase#EmpId}</id>
          </web:employeeId>
       </soapenv:Header>
       <soapenv:Body>
          <web:getEmployeeList>
             <!--Optional:-->
             <param>
                <name>Asim</name>
                <dept>${TestCase#Dept}</dept>
                <joiningDate>2011-10-20</joiningDate>
             </param>
          </web:getEmployeeList>
       </soapenv:Body>
    </soapenv:Envelope>

    Now to use the above request i need to have to create some property variable at TestCase level named as "Dept" & "EmpId".

    And the groovy test step (should be first in the sequence of teststep) will contain following :

    /*
    @Author : Pradeep Bishnoi
    @Description : Randomly read the input value from the input file. Each input value is entered in a new line. So, my file now contains 11 lines/input values.
    */
    def myTestCase = context.testCase

    File empId = new File("d:/my_Input_EmpId.txt")

    File dept = new File("d:/my_Input_Dept.txt")

     List empIds = empId.readLines()

     List depts = dept.readLines()

    def x = Math.random()*10       // multiplying random with 10 so the resulting value would be <= 10.
    i = String.valueOf(x).getAt(0)
    i = i.toInteger()
    myTestCase.setPropertyValue("EmpId", empIds[i])
    log.info context.expand( '${#TestCase#EmpId}' )

    myTestCase.setPropertyValue("Dept", depts[i])
    log.info context.expand( '${#TestCase#Dept}' )

    I hope this will help.

    Best Regards,
    /Pradeep Bishnoi

     
    Gravatar
  • Lakshmi 01/30/2012 04:36 AM

    Hi,

    Thanks for this post. Very informative.

    In this post, the groovy code is reading random text from the text file for a multiple user load. Is it not possible to read values sequentially from the text file like in LoadRunner?

    Random text reading sometimes lead to data reusability for conducting load test. Please help me in providing groovy code for reading values (
    consumerid  and evaluationid )sequentially from a text file in the below SOAP request.

    <soapenv:Body>

          <chal:getTrackerMetaData>

             <chal:consumerid>4</chal:trackerId>

             <chal:evaluationid>5100</chal:userId>

          </chal:getTrackerMetaData>

       </soapenv:Body>

    </soapenv:Envelope>




    Regards
    Lakshmi

     
    Gravatar
  • Pradeep Bishnoi 02/01/2012 05:43 AM

    Hi,

    I feel that another blog would be needed to answer above question. However will give some pointers to achieve the same (till i publish a blog). Following should be created together with content of this blog:

    1. Property test step with a prop named "counter"  with value = 1 
    2. Groovy Script to read the input file & property variable. After reading the input line increment the counter value by 1 & store back into property. If counter value is equal/greater than certain limit value (i.e., number of input data lines available in your input file) then set the counter value = 1.

     

    best regards,

    pradeep bishnoi

     

     
    Gravatar
  • jared 03/01/2012 06:04 AM

    Hello,

    Great post, something I was looking for. However it doesn't 100% work for me. Values are grabbed and randomized correctly, log.info statement displays correct value, but when I send a request a null value is inserted instead of parameter. Can you please confirm that the following line is correct?

    myTestCase.setPropertyValue("inputValue", lines[i])

    Follow up statement works flawlessly:
    log.info context.expand( '${#TestCase#inputValue}' )

    and no error is generated. Respecting part of the request looks as follows:

    <ns4:operationType></ns4:operationType>[\n]




     
    Gravatar
  • swathi 04/26/2012 20:18 PM

    Hi pradeep,
    I 'm new to this..can you pls explain me in detail..how can i get start  with soapui to do load tetsing..My requirement is also need to pull data from external file to soapui to do stress tetsing..can you pls explain where should i add the above script and what should be the approach. It's urgent..TIA

     
    Gravatar
  • Pradeep Bishnoi 05/01/2012 21:51 PM

    @jared : Looks like something wrong with your context expansion in request.

    <ns4:operationType>${#TestCase#inputValue}</ns4:operationType>
    Try this one, hope this will help.

    Regards,
    Pradeep Bishnoi

     
    Gravatar
  • Pradeep Bishnoi 05/01/2012 22:04 PM

    Hi Swathi,

    Hmm... in detail. Follow these steps :
    Create a testcase. Create a testCase level property. Name it "myTestCaseProp".
    Create a TestRequest step. Create a groovy test step. Copy the groovy code into the groovy test step. Create an external source text file in D: drive. Name it as 'my_Input_File.txt'. Put the all values in the text file and make sure that after every value you press Enter. Open the TestRequest step and add ${#TestCase#myTestCaseProp}  between to Xml nodes which you want to parameterize. Navigate to loadtest under testase and run with default setting. Done! Hope this will help.

    Regards,
    Pradeep Bishnoi

     
    Gravatar
  • swathi 05/08/2012 17:03 PM

    Thanks for ur reply pradeep.
    Can you let me know in Soapui pro.. i used datasource step to pull data from txt file.. but here i need to pull random records from the txt file  instead of retriveing records  in sequence manner ....can you pls let me know.. TIA

     
    Gravatar
  • Pradeep Bishnoi 05/10/2012 04:20 AM

    Ok, haven't checked that scenario in soapUI pro version. And now i don't have pro version installted with me. However this should be possible for sure. I remember doing this in past. It would be good if you can post this question in soapUI Pro forum.

    Best Regards,
    Pradeep Bishnoi

     

    Leave a comment:

    1.