July 21, 2021

How to Use BeanShell: JMeter's Favorite Built-in Component

Open Source Automation

JMeter's Beanshell is an advanced — and important — component. In this blog, we'll break down the basics of using Beanshell in JMeter and share practical examples.

Table of Contents: 

 

What Is Beanshell in JMeter?

BeanShell is one of the most advanced JMeter built-in components. It supports Java syntax and extends it with scripting features like loose types, commands, and method closures.

If your test case is uncommon and implementation via embedded JMeter components becomes tricky or even impossible, BeanShell can be an excellent option to achieve your objectives.

See how BlazeMeter can take your JMeter testing to the next level with our free trial.

Start Testing Now

 

JMeter's Beanshell Basics

BeanShell entities in JMeter have access to both internal JMeter APIs and any external classes that are loaded into the JMeter classpath (be sure to drop necessary jars into /lib/ext folder of your JMeter installation and place all necessary “import” statements at the top of your BeanShell scripts).

 

All JMeter versions provide the following BeanShell-enabled components:

 

  • Beanshell Sampler – A standalone sampler
  • Beanshell PreProcessor – A pre-processor to another sampler that is executed before the sampler and can be used for prerequisite setup (i.e. to generate some input). 
  • Beanshell PostProcessor –  A post-processor that is executed after the sampler and can be used for recovery or clean-up.
  • Beanshell Assertion – An advanced assertion with full access to JMeter API. Java conditional logic can be used to set the assertion result.
  • __Beanshell Function – A JMeter Function that allows execution of custom BeanShell code during a sampler run.

 

Changing JMeter Variables on the Fly

 

Assume you have a user-defined variable called "continue" with the value of "true" somewhere in the While loop. You can set it to "false" with this simple command:

 

vars.put("counter","false");

 

Convert JMeter Variable to a JMeter Property

 

Given a variable "some_variable" you must cast JMeter Property with the same name to use, (such as in another thread group).

 

props.put("some_variable",vars.get("some_variable"));

 

Advanced Beanshell in JMeter

 

Passing Cookies between Thread Groups

 

Assuming the HTTP Cookie Manager is enabled, the following code can convert JMeter cookies into JMeter properties.

 

import org.apache.jmeter.protocol.http.control.CookieManager;
 

CookieManager manager =

ctx.getCurrentSampler().getProperty("HTTPSampler.cookie_manager").getObjectValue();

 

props.put("cookiecount",String.valueOf(manager.getCookieCount()));

 

for (int i=0;i                  // code to convert Cookie information to JMeter Properties
    props.put("cookie_name_" + i, manager.get(i).getName());
    …..
}
 

After all cookie information is stored as a JMeter property, you can reconstruct cookies in another thread group.

 

import org.apache.jmeter.protocol.http.control.CookieManager;

import org.apache.jmeter.protocol.http.control.Cookie;
import org.apache.jmeter.testelement.property.JMeterProperty;

 

CookieManager manager =

ctx.getCurrentSampler().getProperty("HTTPSampler.cookie_manager").getObjectValue();



int count = Integer.parseInt(props.getProperty("cookiecount"));

 

for (int i=0;i        Cookie cookie = new

Cookie(props.getProperty("cookie_name"+i),props.getProperty("cookie_value"+i), props.getProperty("cookie_domain"+i),props.getProperty("cookie_path"+i), Boolean.parseBoolean(props.getProperty("cookie_secure"+i)), Long.parseLong(props.getProperty("cookie_expires"+i)));
manager.add(cookie);
}
 

JMeterProperty cookieprop =

ctx.getCurrentSampler().getProperty("HTTPSampler.cookie_manager");
cookieprop.setObjectValue(manager);
ctx.getCurrentSampler().setProperty(myprop);

 

Stopping the Test in Case of Failure

 

Imagine you have a 48-hour SOAK test scheduled to run over the weekend that explicitly depends on a CSV data set config element that requires source CSV files to be present. You tested it with one user and one loop on your developer machine, and it worked fine. However, when you upload it to your production environment and run headless, JMeter fails to locate the CSV file and all 48 hours are wasted. To avoid this situation, use the following check in the very first BeanShell Sampler:

 
File mycsvfile =new File("my.csv");

 

if(!mycsvfile.exists()){

      SampleResult.setSuccessful(false);

      SampleResult.setResponseMessage("Failed to find my.csv file");

      SampleResult.setResponseData("Unable to locate my.csv file under path: " + mycsvfile.getPath(),"UTF-8");

      IsSuccess=false;

      SampleResult.setStopTestNow(true);

}

 

Example: JMeter, Beanshell, and BlazeMeter

 

This example demonstrates a simple BeanShell use case with BlazeMeter under the following TestPlan structure:

 

  • Thread Group (1 user, 1 second ramp-up, forever)
  • While Controller with empty condition  (forever)
    • Counter (start – 1, increment  – 1, reference name – counter)
    • HTTP request (server name – example.com)
      • BeanShell Post Processor 

 

The BeanShell post-processor tests if the HTTP sampler response contains the example domain. If it doesn’t, the test will fail and stop immediately. If it does, the test will stop after the third iteration. In both cases, something is appended to the jmeter.log.  

 

String response = new String(data);
int counter = Integer.parseInt(vars.get("counter"));

 

log.info("Starting iteration: " + counter);
log.info("Checking for \"Example Domain\" presense in response");

 

boolean found =response.contains("Example Domain");
log.info("Found - " + found);

 

if (!found)
{
prev.setSuccessful(false);
String errormsg = "\"Example Domain\" string isn't present in response";
prev.setResponseMessage(errormsg);
log.error(errormsg);
prev.setStopTestNow(true);
}

 

if (counter == 3)
{
log.info("Reached third iteration, stopping test");
log.error("Test ID " + props.get("blazemeter.test_id") + " ended at " + new Date());
stopTest();
}

 

void stopTest()
{
prev.setStopTest(true);
}

 
An example of JMeter Beanshell Post Processor in BlazeMeter.
 
                                                                                                                                                 

How to Use JMeter Beanshell Predefined Variables

 

The next section contains the most important and most frequently used JMeter API classes exposed to BeanShell components. If you look at the bottom of BeanShell sampler component, you’ll see following:

“The following variables are defined for the script:

 

SampleResult, ResponseCode, ResponseMessage, IsSuccess, Label, FileName, ctx, vars, props, log”

 

SampleResult

 

SampleResult maps to the JMeter class org.apache.jmeter.samplers.SampleResult. All fields and methods outlined in the javadoc can be accessed and invoked.  Here is a sample use-case:

 

String currentURL = SampleResult.getUrlAsString();

 

ResponseCode

 

ResponseCode is a java.lang.String that stands for sampler response code. Here is a sample use-case:

 

if(condition){

            ResponseCode = "200";

}

else{

            ResponseCode = "500";

}

 

ResponseMessage

 

ResponseMessage is a java.lang.String that represents a response message. The sample use case is the same as the one for the ResponseCode.

 

IsSuccess

 

IsSuccess is a java.lang.Boolean that reflects whether sampler succeeded. If it’s set to true, sampler is considered “passed.” Otherwise, it will be marked as “failed.”

 

if(condition){

            IsSuccess =true;

}

else{

            IsSuccess =false;

}

 

Label

 

Label is java.lang.String that represents sampler label. It can be get or set as a usual String and will be listed in the test results as a sampler label. 

 

FileName

 

FileName is a java.lang.String that contains a BeanShell script file name (what is entered in “Script file” stanza of the BeanShell Sampler). 

 

ctx

 

ctx is the most powerful variable exposed to BeanShell. It represents the  org.apache.jmeter.threads.JMeterContext class, which is virtually JMeter itself. It provides read/write access to the underlying JMeter engine, samplers, and their results as well as variables/properties. 

 

vars

 

vars (JMeter variables) is the most frequently used component. It’s an instance of the org.apache.jmeter.threads.JMeterVariables class and provides read/write access to current variables, is capable of enumerating/changing existing variables, creating new ones, and obtaining nested properties.  All JMeter variables are Java strings. If you need to put something else to a JMeter variable, you’ll need to cast it to string first. The following code snippet demonstrates how to save previous sampler response data into a JMeter variable.

 

byte [] samplerdata = ctx.getPreviousResult().getResponseData();

String samplerdatastring =new String(samplerdata);

vars.put("samplerdata",samplerdatastring);

 

props

 

Basically, this is the same as “vars,” but it exposes JMeter properties instead. See JavaDoc on java.util.Properties and JMeter documentation on JMeter properties for more information. The primary distinction between props and vars is that props have a “global” scope, whereas the scope of “vars” is limited to the current thread group. 

 

log

 

log represents the org.apache.log.Logger class and can be used to append a message into jmeter.log file. See JavaDoc on logger for more details. The following is the sample use case:

 
log.info("This is a message with INFO level");

log.error("This is a message with ERROR level");

 

How to Debug Beanshell Scripts

 

As BeanShell is executed within the Rhino engine, there is no other option to see what’s wrong, apart from inspecting jmeter.log file for something like:

 

Error invoking bsh method 

 

and using System.out.println(“something”) or log.info(“something”) to determine where the script fails.

 

Strengthen JMeter Beanshell With BlazeMeter

While JMeter represents a strong and compelling way to perform load testing, of course, we recommend supplementing that tool with BlazeMeter, which lets you simulate up to millions of users in a single developer-friendly, self-service platform.  With BlazeMeter, you can test the performance of any mobile app, website, or API in under 10 minutes.  Here’s why we think the BlazeMeter/JMeter combination is attractive to developers:

  • Simple Scalability – It’s easy to create large-scale JMeter tests. You can run far larger loads far more easily with BlazeMeter than you could with an in-house lab.
  • Rapid-Start Deployment – BlazeMeter’s recorder helps you get started with JMeter right away, and BlazeMeter also provides complete tutorials and tips.
  • Web-Based Interactive Reports – You can easily share results across distributed teams and overcome the limitations of JMeter’s standalone UI.
  • Built-In Intelligence – BlazeMeter provides on-demand geographic distribution of load generation, including built-in CDN-aware testing.

This post was recently published and was updated for accuracy in July 2021.

START TESTING NOW