Friday, March 19, 2010

Dynamic Parameters in JMeter

Motivation
You need to send a variable number of parameters with an HTTP request i.e. the number of parameters are not known when the script is written. For example a User can register with a number of accounts , but this number varies per user. Or perhaps you want to Post process extract a number of hidden fields on the previous response and post all of them in the next Request, but you either don't know the number or there are too many fields to enter manually into the HTTPSampler.

Solution
Use a BeanShell PreProcessor to dynamically add variables to the sampler. The relevant code is sampler.addArgument(name,value)[1]

Sample
We will write a script to access a page , extract out data based on a pattern and send these as separate parameters to the next request. The script is as shown below.
We make a request to some dummy page and then we have a regex extractor to extract out multiple values. In this case the Regex extracts out all words(Match No = -1) beginning with test




Then we have a Debug Sampler to verify the regex is working, notice the results in View Results Tree Listener. The Regex has a reference variable name of inputTerms. The response of the Debug sampler is shown below

You can see from the Listeners response tab that the total number of results is 14 , available under the key inputTerms_matchNr and that each result is available as inputTerms_$resultnumber.
The matching groups which we usually do not need are available as inputTerms_$resultnumber_g$groupnumber. Armed with this information, the beanshell preprocessor script is trivial as shown below
int count = Integer.parseInt(vars.get("inputTerms_matchNr"));
for(int i=1;i<=count;i++) { //regex counts are 1 based
sampler.addArgument("hardcodedkey", vars.get("inputTerms_" + i));
}
Heres the next request to which the beanshell pre processor is attached. We have one predefined variable and the rest will be dynamically added by beanshell.

Next we check the request data we are posting using the Request tab of the View Results Tree Listener



Notice that the argument we added to the next request was sent, as were all the parameters we added dynamically. The parameter values were also encoded.
Sample Script : https://skydrive.live.com/#cid=1BD02FE33F80B8AC&id=1BD02FE33F80B8AC!268

26 comments:

Anonymous said...

Great article. Thanks!
Alex

Anonymous said...

great!!!!

RRP said...

Nice article... will help a lots of guys in need..
It helped me...

Saurabh Thakur said...

Nice short article ..would love to see more on Usage of Beanshell in Jmeter.

Anonymous said...

you cant beieve how lucky i am to have found this article. really really good. thank you so much!

Anonymous said...

i am new to jmeter. Will u plz post the step by step procedure to run this script.
Thanks in advance.

Deepak Shetty said...

@anonymous
Download script from https://skydrive.live.com/#cid=1BD02FE33F80B8AC&id=1BD02FE33F80B8AC!268

The script name is dynamic parameters. launch Jmeter and open this script file and run it.

Note that you rarely need to add parameters dynamically (typically you know what parameters and how many there are in the script so you can directly specify them)

Karthik said...

Thanks you very much mate. I've been scratching my head like hell to figure out how to add variable number of parameters dynamically. This helped me a lot.
Karthik

Anonymous said...

Awesome Work buddy. That's what I was looking for.

Thanks Again.

siva said...

hi, i have multiple select tags and i wanna get option value based on select tag id attribute value using regular expression.

Deepak Shetty said...

@Siva
XPath Post processor is usually easier in such cases (but less memory efficient and slower)
It might still be possible to do it with regex but the regex itself is much more difficult. The other option is using the id extract out the Select HTML. Then write a second regex that operates on this extracted Select box to extract out the option

Nabojyoti Sarkar said...

Hi Deepak

Excellent post mate!!!

Just wanted to know that what needs to be done if I do not want to hardcode the value of the paarameter..say I want the parameters to contain values from a predefined CSV file..Could you please help me onm this?
Thanks
Nabojyoti(sarkar.nabojyoti@gmail.com)

Deepak Shetty said...

@Nabojyoti Sarkar
The API allows you to specify whatever key/value you want and JMeter/java allow you to write whatever logic you want.

For e.g. if your CSV is read using a CSV data set config and you have 4 columns(column1 = name of parameter,column2=value of the same parameter) which map to variables col1 ,col2,col3,col4

then in the Beanshell pre processor you could write

sampler.addArgument(vars.get("col1"),vars.get("col2"));

Again the main point is sampler.addArgument(key,value)
How you get key and value isnt really relevant and can be done in many different ways

Nabojyoti Sarkar said...

Thanks a lot Deepak for your response..thanks for helping me understanding the working of this API, however, I am unable to do something using this. I aim at generating random number of paramaters (successfully done that with your help) and then assign values to the parameters from a csv file. The csv file has two columns and few rows. I want the first parameter to get value from cell(row1,col1), second parameter to get value from cell(row2,col1) and like wise...can you pls provide me the code how to do this? Currently it is only populating the parameters with the values present in cell (row1,col1)

Deepak Shetty said...

@Nabojyoti
Usually your excel file should be modelled as
row1 = data for 1 case
row2 = data for 1 case
i.e. each row should have the data .
In your example you want the column to have the data - its easier if you transpose your excel.
If you can then simply use the CSV Data Set Config
Thread Group
+While Controller (with condition)
++HTTP request Sampler
+++BeanShell Preproc
++CSV Data Set config(var1,var2...)

Then for each time the while controller runs the values you declare in the variables (in the example var1, var2) will move to the next row.
Because the reading is row by row what you want is the data for one test case to be contained in the row so parameter 1 = row1,col1
parameter 2 = row1, col2

You need to specify the sharing mode on CSV data set config and you also need to provide a condition when you want to stop (for e..g. if you want to stop when there are no more lines in the CSV then you use "${var1}" != ""



Rachna said...

Awesome soved my problems in a seconds :) :) Thanks a ton

krishna said...

@deepak


HI bro, can u explain me how to read an excel file using beanshell

Deepak Shetty said...

@krishna
Not related to this post - please send jmeter questions to the jmeter mailing list.
easiest way is to export excel to CSV and use CSV in JMeter. other way is to use POI or JExcelAPI to read the file and iterate using beanshell or custom elements - however that is too much to describe in a comment

Sattish said...

Hi Deepak,

Thanks for this nice article. It helped me a lot

Sattish.

Anonymous said...

Great article.
It helps me a lot!

Anonymous said...

God bless you. Very Very Helpful Articles.

Anonymous said...

Thank you, thank you, thank you, thank you.

Anonymous said...

HI
It thorows an error while executing
ERROR - jmeter.util.BeanShellInterpreter: Error invoking bsh method: eval Sourced file: inline evaluation of: ``int count = Integer.parseInt(vars.get("inputTerms_matchNr")); for(int i=1;i<=cou . . . '' : Typed variable declaration : Method Invocation Integer.parseInt

Deepak Shetty said...

@Anonymous
Is this your full script? most likely your variable is not called inputTerms (reference name in your regex ) or your regex is messed up or something.
Did you look at the result of debug sampler to check that the values are getting extracted as you expect?

Anonymous said...

Hi Deepak
Thanks Deepak for the response.In bean shell post processor,the script what I have mentioned is int count = Integer.parseInt(vars.get("Input Terms_matchNr"));
and in the HTTP request i'm passing the parameter "${count}" in the value section.

Note:Now the error is solved.But no value is captured in ${count} when i checked the view result tree.I'm expecting the value "8" for "count".For the response for the earlier request the value shown for "inputTerms_matchNr" is "8" and it is shown in debug sampler.

Deepak Shetty said...

as mentioned you need to check your script (variable name of Input Terms with a space in it looks wrong) - steps to debug were also specified in previous response. Basically you are not returning a parseable number so Integer.parseInt is failing