beanshell property not updated in subsequent iteration of While Controller - properties

I have a JMeter test which should execute a fixed number of REST calls executed by a configurable number of users concurrently. So depending on the responsetime of the REST call, one user may have executed a slightly more number of REST calls than an other user.
To do this i have created a Beanshell PreProcessor with a script. This script copies the value from a user defined variable maxdocumentuploads to the property documentuploads.
props.put("documentuploads",${maxdocumentuploads})
log.info(">>>INIT> " + props.get("documentuploads"));
In a Thread Group a While Controller is created with condition ${__groovy(props.get("documentuploads") > 0 )}. The first child of the While Controller is a BeanShell PreProcessor with a script that reads the property, decrements the value of the property and puts the decremented value.
log.info(">>>GET> " + props.get("documentuploads"));
int counter = props.get("documentuploads") ;
counter--;
log.info(">>>INC> " + counter);
props.put("documentuploads", counter);
log.info(">>>CHK> " + props.get("documentuploads"));
Simplified the Testplan is setup like this;
Test Plan
+ init counter (Beanshell PreProcessor)
+ Users (Thread Group)
+ While Contoller
+ BeanShell PreProcessor
The log.info shows that the property is updated with the new value, but on each iteration the value of the property is back to the initial value.
The BeanShell PreProcessor 'init counter' is executed on each iteration of the While Controller. How can i initialize a property on start of a test plan with the value of a test plan User Defined Variable without having it re-set each iteration of the while controller.

Add parent for preprocessor so it will execute once before parent
Put as parent Flow Control Action with Duration, which will do nothing except executing the beanshell script
Consider changing beanshell to JSR223 script
Another option is to add as parent an If Controller and check while controller's counter
Another option is to use Sampler instead of PreProcessor so it will executed once.

Related

Saving a max value of counter to file in JMeter

I'm using a SOAP/XML-RPC Request to test a WSDL. Additionally I created a Counter element for this request. Each call of one of the functions has to contain other value in one of parameters.
Is there any possibility to save the maximum counter value to the file?
So when I start test, the value will be loaded from the file and increase by the counter.
At the end, this max value will be again saved to this file. And so on, so on...
Let's drop the built-in Counter and pass around the thread safe AtomicInteger.
Add a setUp Thread Group with a JSR223 Sampler (choose groovy as a scripting language) to your test plan. We will use it to read the value from the file. This thread group will be executed before all other thread groups and will provide us with the initial value.
Add the following code to the sampler:
import java.util.concurrent.atomic.AtomicInteger
counter = new File($/C:\Path\ToFile\fileName.txt/$).text
ai = new AtomicInteger(Integer.valueOf(counter))
props.put("sharedAtomicInteger", ai)
Then add another JSR223 Sampler after SOAP/XML-RPC Request in your regular Thread Group.
Add the following code to the sampler:
ai = props.get("sharedAtomicInteger")
variable = ai.incrementAndGet()
vars.put("variable", Integer.toString(variable))
Now the value of the improvised counter is stored in a variable and can be used in other requests issued by this thread.
Add a tearDown Thread Group with a JSR223 Sampler to your test plan. This thread group will be executed after all other thread groups and will write the maximum value to the file.
Add the following code to the sampler:
ai = props.get("sharedAtomicInteger")
new File($/C:\Path\ToFile\fileName.txt/$).write(ai.toString())
Finally, your test plan should look like this:
setUp Thread Group
JSR223 Sampler
Regular Thread Group
SOAP/XML-RPC Request
JSR223 Sampler
tearDown Thread Group
JSR223 Sampler
P.S.
Bear in mind that for brevity's sake I used the put() method of java.util.Properties class which is discouraged in the documentation.
To save value into a file (assumes a JSR223 Element and Groovy language)
new File("value.txt").text = vars.get("foo")
To read the value from file (assumes __FileToString() function)
${__FileToString(value.txt,,)}
I used tips from the first comment and do it in the following way:
transfer - Simple Controller
reading transactionId - JSR223 PreProcessor
transfer - SOAPXML-RPC Request
saving transactionId - JSR223 PostProcessor
JSR223 PreProcessor
Script language: groovy
import java.util.concurrent.atomic.AtomicInteger;
initial = new File("${absolute_path}transactionid.txt").text;
initial = initial.trim();
ai = new AtomicInteger(Integer.valueOf(initial));
transactionId = ai.incrementAndGet();
vars.put("transactionId", Integer.toString(transactionId));
SOAPXML-RPC Request
Here I'm using transactionId as one of the parameters in the SOAP Request.
JSR223 PostProcessor
Script language: groovy
transactionId = vars.get("transactionId");
new File("${absolute_path}transactionid.txt").write(transactionId.toString());
${absolute_path} is a variable defined in test plan as:
${__BeanShell(import org.apache.jmeter.services.FileServer; FileServer.getFileServer().getBaseDir();)}${__BeanShell(File.separator,)}
It is a path to folder with this JMeter project. This folder also contains file which is read to this test case.

BeanShell PreProcessor updates User define variables

I'm very new at JMeter issues.
In a test script i have a BeanShell PreProcessor element that updates some variables previously defined at a "User Defined Variables" element.
Latter those variables are used in "Http Requests". However, the value that is used in the http request is the default one.
The scripts seems to be working due to some debug print();
My question is if it's necessary to delay the script to be sure that the BeanShell finishes?
Thanks a lot for your attention
There is no need to put any delay to Beanshell Pre-Processor as it's being executed before request. I'd recommend to check your jmeter.log file to see if there are any scripting issues as Beanshell Pre-Processor does not report errors anywhere including View Results Tree listener.
There are at least 2 ways to assure that everything is fine with your Beanshell script:
Put your debug print code after variables replace logic to see if it fires
Use JMeter __Beahshell function right in your HTTP request. If it's ok - View Results Tree will demonstrate beanshell-generated value. If not - the field will be blank and relevant error will be displayed in the log.
Example test case:
Given following Test Plan structure:
Thread Group with 1 user and 1 loop
HTTP GET Request to google.com with path of / and parameter q
If you provide as parameter "q" following beanshell function:
${__BeanShell(System.currentTimeMillis())}
and look into View Results Tree "Request" tab you should see something like:
GET http://www.google.com/?q=1385206045832
and if you change function to something incorrect like:
${__BeanShell(Something.incorrect())}
you'll see a blank request.
The correct way of changing existing variable (or creating new if variable doesn't exist) looks like
vars.put("variablename", "variablevalue");
*Important: * JMeter Variables are Java Strings, if you're trying to set something else (date, integer, whatever) to JMeter Variable you need to cast it to String somehow.
Example:
int i = 5;
vars.put("int_i", String.valueOf(i));
Hope this helps.
You can update the vale of a "user defined variable".
You have to create a bean shell sampler
vars.put("user_defined_variable", "newvalue");
#theINtoy got it right.
http://www.blazemeter.com/blog/queen-jmeters-built-componentshow-use-beanshell
I'm new to jmeter too but as I know variables defined in "User defined variables" are constants, so you can't change them. I recommend to use "User Parameters" in preprocessors or CSV Data Set Config.

sharing variables between beanshell scripts

I want to have some kind of an initialization in 1 particular beanshell script , which is later used in 2 other bsh scripts. Now , the initialization thus takes place twice.
Is there some way to share variables/namespace between beanshell scripts so that the initialization takes place only once ?
Look at the object "bsh.shared".
if(bsh.shared.myList == void)
bsh.shared.myList = new java.util.ArrayList();
// Do stuff to the List anywhere as follows:
//
bsh.shared.myList.add("foo");
Can you create a BeanShell script that performs the initialisation and load it into your other scripts via source ?

soapUI: property not used in property expansion in a test case

I'm using soapUI 3.6.1 and I want to test a SOAP-interface with a test structure like this:
MyWorkspace
MyProject
TestSuite
TestCase Single
TestStep 1
TestCase Loop
Properties #1
Groovy #1
Run TestCase Single
Properties #2
Groovy #2
Run TestCase Single
TestCase Single contains a bunch of requests that should be performed with the same account-id. TestCase Loop is supposed to call TestCase Single using different account-ids. The Properties * are supposed to change the account-id.
MyProject has a property accountId set up with value 1234. This should work as the default value for single testing of the test cases, i.e. TestCase Single.
Properties #1 and Properties #2 have accountId specified with different values.
The intention is to allow TestStep 1 to be executed alone or as part of TestCase Loop.
TestStep 1 has a common SOAP-body where the following is a parameter sent to the web-service:
<accId>${='${#accountId}' != '' ? '${#accountId}' : ${#Project#accountId}}</accId>
Groovy #1 and Groovy #2 look like this:
log.info('Using account ' + (context.expand('${#accountId}') != '' ? context.expand('${#accountId}') : context.expand('${#Project#accountId}')));
My problem now is that the Groovy-script writes the correct value of accountId (i.e., the one inside the loop), but the TestStep 1 always uses the value from the project. I want TestStep 1 to use the value of the loop.
For debugging purposes I also put the following into TestStep 1:
<!--
{#Project#accountId}: ${#Project#accountId}
{#TestSuite#accountId}: ${#TestSuite#accountId}
{#TestRunContext#accountId}: ${#TestRunContext#accountId}
{#TestRun#accountId}: ${#TestRun#accountId}
{#TestCase#accountId}: ${#TestCase#accountId}
{#TestStep#accountId}: ${#TestStep#accountId}
{#MockService#accountId}: ${#MockService#accountId}
{#Global#accountId}: ${#Global#accountId}
{#System#accountId}: ${#System#accountId}
{#Env#accountId}: ${#Env#accountId}
{#accountId}: ${#accountId}
context.accountId: ${=context.accountId}
modelItem.accountId: ${=modelItem.accountId}
request.accountId: ${=request.accountId}
context.expand(): ${=context.expand('${#accountId}')}
-->
I traced the network traffic with Wireshark and noticed that only ${#Project#accountId} returned a value.
What am I doing wrong here? How do I need to code the <accId>-element to send the correct value to the remote host?
Now I revisited this issue and I think I found the best possible solution, even though I don't understand why my initial attempt didn't work.
I changed the structure to this:
MyWorkspace
MyProject
TestSuite
TestCase Single
TestStep 1
TestCase Loop
Groovy #1
Run TestCase Single
Groovy #2
Run TestCase Single
In other words I got rid of the Properties and moved the logic into the Groovies:
context.getTestCase().getTestSuite().setPropertyValue("accountId_loop", "1720");
and the appropriate line in TestStep 1:
<accId>${='${#TestSuite#accountId_loop}' != '' ? '${#TestSuite#accountId_loop}' : ${#MyProject#accountId}}</accId>

jmeter - showing the values of variables

My group does a lot of test automation with JM. Typically we have a properties file which has a bunch of variables defined. These in turn are mapped to "User Defined Variables" of which we have a number of different sets.
These are in referenced throughout the rest of the jmx - I find it difficult as there are so many variables in so many different places to know what is what. Is there any way to have jmeter display what values its variables have - custom sampler is fine ? Ideally id love it if you could just hover a var and have its value displayed.
Any ideas ?
The newest versions of Jmeter have a fantastic sampler called "Debug Sampler" that will show you the values for: Jmeter Variables, Jmeter Properties or System properties.
You can insert them wherever you want in the script to get values at a given time. You'll want to have a "View Results Tree" enabled to view the sampler.
Given that Jmeter declares variables from a file on run, you won't be able to get your ideal solution.
I'm curious...would it be cleaner to employ "CSV Data Set Config" rather then populating "User Defined Variables" from a properties file?
Edit: Added explanation on variable declaration and asked CSV question.
Here is how I used to get Set of vars right through the code (variant with Java code in JSR223 PostProcessor):
Add "JSR223 PostProcessor" by right click wherever you need to check jMeter variables in your project;
Set Language (in my case - to java);
Add following code to Script window:
import java.util.Map;
String jMeterVars;
jMeterVars = "Quantity of variables: " + vars.entrySet().size() + ".\n\n";
jMeterVars += "[VARIABLE NAME] ==>> [VARIABLE VALUE]\n\n";
for (Map.Entry entry : vars.entrySet()) {
jMeterVars += entry.getKey() + " ==>> " + entry.getValue().toString() + "\n";
}
try {
FileWriter fw = new FileWriter("D:\\jMeterVarsForStackOverflow.txt",true);
fw.write(jMeterVars);
fw.close();
} catch(IOException ioe) {
System.err.println("IOException: " + ioe.getMessage());
}
Check that everything in the JSR223 PostProcessor looks like that:
Start your project in jMeter.
The code above will create jMeterVarsForStackOverflow.txt file at D: and put all variables there: