Apache Groovy is a scripting language that has become the default option in JMeter JSR223 elements. To accommodate that, the Groovy library has been included by default in JMeter ever since version 3, and no manual steps need to be performed to use it. Previous JMeter versions required downloading Groovy and manually including it in JMeter libraries.

Groovy has become the recommended scripting language for JMeter because it’s easy to use, it is flexible and it is constantly being developed. In addition, Groovy can be fully integrated with Java, which provides many scripting capabilities via an expressive, concise and readable syntax. You can read more information about Groovy and why we recommend choosing it from this blog post Apache Groovy - Why and How You Should Use It.

When developing simple scripts of a very low load, JMeter’s Javascript or Beanshell engines provide good performance. On the other hand, if the script is called by several threads, the JSR223 Groovy engine performs much better and with less overhead. This means that JMeter will execute the Groovy script faster, resulting in a lower response time.

Why is this the case? Because each Beanshell sampler has its own copy of the Java interpreter for each thread, which will be loaded in your system’s memory on each iteration of your test run, thus adding overhead. On the other hand, Groovy implements the Compilable interface, meaning that it can be executed repeatedly without recompilation. This behavior is further explained in the blog post Beanshell vs JSR223 vs Java JMeter Scripting: The Performance-Off You've Been Waiting For!.

Now we will explain how Groovy scripts can be developed and integrated in the relevant JMeter elements: the JSR223 Pre Processor, the JSR223 Post Processor and the JSR223 Sampler.

Groovy Scripts Structure

The following structure is recommended to follow programming good practices:

Import statements are included at the beginning of the script for any of the classes that will be used:

import org.apache.jmeter.services.FileServer

Import statements allow including specific members of a package in your script. In this example, the FileServer is referred in the script, and now all the functions implemented in it can be used.

Next, add variable definitions. This is where you should set the variables that will be used in the script. Some variables are used locally in the script while others are used to get JMeter Test plan defined variables values.

In order to set a Groovy script variable with a JMeter variable value, the vars.get() method must be used as followed:

def month = vars.get(“month”)

It is not necessary to declare the definition type for the variables.

Finally, write down the statements that develop your script. The following presents a summarized list of statements:

if, if/else, switch - for decision making

while, for, for-in - for loops

break, continue - for loops control

Arithmetic, relational, logical, bitwise and assignment operators

Now, let’s look at a short example of a Groovy script where the vars.put("variable", "value") method is used to set a value to a JMeter variable. Here, the variable value to be used on an assertion, is loaded from a file:

import org.apache.jmeter.services.FileServer //File paths relative to script directory def inputPath = FileServer . getFileServer (). getBaseDir () + "\\data\\assertion.txt" //Load the file into the inputFile variable File inputFile = new File ( inputPath ) //Next, if the file exists, first log a message and then load the JMeter variable “assertionValue” // with the contents of the file if ( inputFile . exists ()) { log . info ( "File " + inputPath + " exists" ) vars . put ( "assertionValue" , inputFile . text ) }

Using Groovy in JMeter

When it comes to improving JMeter’s functionality, Groovy has proven to be a powerful, and yet lightweight, language in terms of performance. We will now present examples where JMeter’s functionality is improved with Groovy.

In each of the following, JMeter JSR223 elements are used with Groovy scripting language, as shown below:

JSR223 PreProcessor

PreProcessor elements are executed before requests are sent in a test. Let’s look at an example with Groovy:

We will take a CSV file with transaction data, in the following format:

date,user_id,transaction_id,amount

28/11/2017,34505434,94028557488,42

We will use Groovy to filter transactions for a specific month and year, which are defined as variables in the JMeter script. Each line of the input file will be read, and when a transaction match is found in the date fields, it will be written to an output file.

Groovy lets us easily work with files and filter lines based on specific criteria. This example focuses on reading each line, by using the the File.eachLine() function. Then, it uses String.split(), with a comma as a field separator, and finally String.endsWith(), to compare the date field.

Results are written into an output file, which is created if it does not exist yet. Lines are appended to the end by using the left shift operator (<<).

//Script to process a CSV file with transactions in the following format: //date,user_id,transaction_id,amount //13/12/2017,34505434,94028557488,42 //First, FileServer class is imported so it can be used later import org.apache.jmeter.services.FileServer //File paths relative to script directory are loaded for both input and output files def inputPath = FileServer . getFileServer (). getBaseDir () + "\\data\\transactions.csv" def outputPath = FileServer . getFileServer (). getBaseDir () + "\\data\\transactionsToProcess.csv" //Create a new File instance by using the path defined File inputFile = new File ( inputPath ) //Load JMeter variable values from month and year into the script via the vars.get() method def month = vars . get ( "month" ) def year = vars . get ( "year" ) //The following variables are declared and will be later used def words def date def line //check if the file exists if ( inputFile . exists ()) { //log an information message that the file is readable log . info ( "File " + inputPath + " exists" ) //Create a new output file instance with the defined path File outputFile = new File ( outputPath ) //for each line of the file inputFile . eachLine { line -> //Load the contents of the actual line into a words array using a comma as the // word separator and then load the first element into the date variable words = line . split ( "," ) date = words [ 0 ] //Evaluate if the date matches the month and year to be filtered and, if true, write //the line into the output File if ( date . endsWith ( month + "/" + year )) outputFile << line + "

" } }

JSR223 PostProcessor

PostProcessor elements perform actions after the samplers are executed. In this example, HTTP response bodies and the thread name are saved in a response text file, by using the JMeter JSR223 PostProcessor element. Groovy is used to read the body and the thread name from the previous JMeter element.

//First, the FileServer class is imported so it can be used later import org.apache.jmeter.services.FileServer //Create a new File instance by using the path defined def inputPath = FileServer . getFileServer (). getBaseDir () + "\\responseFile.txt" //Get the body from the response: def body = prev . getResponseDataAsString (); //Create the response file: def responseFile = new File ( inputPath ); //Get the thread name: def sample = prev . getThreadName (); //Write the thread name: responseFile << "----------------------------------------------------------------------------------------

" ; responseFile << " " + sample + "

" ; responseFile << "----------------------------------------------------------------------------------------

" ; //Write the data into the file: responseFile << body ;

This script generates the following output on the responseFile file (output truncated):

---------------------------------------------------------------------------------------- Thread Group 1 - 1 ---------------------------------------------------------------------------------------- <! DOCTYPE html > <!--[ if IEMobile 7 ]> < html class = "iem7" lang = "en" dir = "ltr" ><![ endif ]--> <!--[ if lte IE 6 ]> < html class = "lt-ie9 lt-ie8 lt-ie7" lang = "en" dir = "ltr" ><![ endif ]--> <!--[ if ( IE 7 )&(! IEMobile )]> < html class = "lt-ie9 lt-ie8" lang = "en" dir = "ltr" ><![ endif ]--> <!--[ if IE 8 ]> < html class = "lt-ie9" lang = "en" dir = "ltr" ><![ endif ]--> <!--[ if ( gte IE 9 )|( gt IEMobile 7 )]><!--> < html lang = "en" dir = "ltr" prefix = "og: http://ogp.me/ns# article: http://ogp.me/ns/article# book: http://ogp.me/ns/book# profile: http://ogp.me/ns/profile# video: http://ogp.me/ns/video# product: http://ogp.me/ns/product# content: http://purl.org/rss/1.0/modules/content/ dc: http://purl.org/dc/terms/ foaf: http://xmlns.com/foaf/0.1/ rdfs: http://www.w3.org/2000/01/rdf-schema# sioc: http://rdfs.org/sioc/ns# sioct: http://rdfs.org/sioc/types# skos: http://www.w3.org/2004/02/skos/core# xsd: http://www.w3.org/2001/XMLSchema#" ><!--<![ endif ]-->

JSR223 Sampler

JMeter Sampler elements allow taking actions in any place in the test, without depending on a specific request.

In this example a JSR223 sampler will be used to send HTTP requests to either BlazeMeter or JMeter websites, based on the thread id. The thread id is the number of threads and its name, and the Thread class is used to get this information.

This sampler is placed right above the HTTP request in the JMeter tree, so the thread has the “server” variable properly set.

//Get current thread Thread thread = Thread . currentThread (); //Debug using log.info log . info ( "Runnable Job is being run by " + thread . getName () + " (" + thread . getId () + ")" ); //Get thread Id Long threadNum = thread . getId (); //If thread Id is even, request Blazedemo page, if not, request JMeter page if ( threadNum . mod ( 2 ) == 0 ){ vars . put ( "server" , "www.blazedemo.com" ); } else { vars . put ( "server" , "jmeter.apache.org" ); } return "Next request will be to server: " + vars . get ( "server" );

The log viewer panel will show:



... 017 /12/ 29 10 : 42 : 53 INFO - jmeter . threads . JMeterThread : Thread started: Thread Group 1 - 1 2017 /12/ 29 10 : 42 : 53 INFO - jmeter . protocol . java . sampler . JSR223Sampler : Runnable Job is being run by Thread Group 1 - 1 ( 155 ) 2017 /12/ 29 10 : 42 : 53 INFO - jmeter . protocol . java . sampler . JSR223Sampler : Thread is requesting: jmeter . apache . org 2017 /12/ 29 10 : 42 : 54 INFO - jmeter . threads . JMeterThread : Thread started: Thread Group 1 - 2 2017 /12/ 29 10 : 42 : 54 INFO - jmeter . protocol . java . sampler . JSR223Sampler : Runnable Job is being run by Thread Group 1 - 2 ( 156 ) 2017 /12/ 29 10 : 42 : 54 INFO - jmeter . protocol . java . sampler . JSR223Sampler : Thread is requesting: www . blazedemo . com 2017 /12/ 29 10 : 42 : 54 INFO - jmeter . threads . JMeterThread : Thread is done: Thread Group 1 - 1 2017 /12/ 29 10 : 42 : 54 INFO - jmeter . threads . JMeterThread : Thread finished: Thread Group 1 - 1

How Groovy Helps Debugging

In most of the examples, the log.info() function is used to write relevant information into the log. This is a good practice for debugging purposes. The functions log.warn() and log.error() can also be used depending on the message to be logged. We will now illustrate how to improve your debugging by the use of these functions.

This example extends the Preprocessor one detailed previously, by adding a sentence if the file to be read in the filesystem does not exists. The following line is added at the end of the script:

if ( inputFile . exists ()) { ... } else log . error ( "Unable to open " + inputPath )

In case the inputFile to be read is not accessible, an error message will be logged and the alert icon on the top right will be increased by one:

... 2017 /12/ 29 14 : 03 : 24 INFO - jmeter . engine . StandardJMeterEngine : All thread groups have been started 2017 /12/ 29 14 : 03 : 24 INFO - jmeter . threads . JMeterThread : Thread started: Thread Group 1 - 1 2017 /12/ 29 14 : 03 : 24 INFO - jmeter . services . FileServer : Stored: data /transactionsToProcess.csv 2017/ 12 /29 14:03:24 ERROR - jmeter.modifiers.JSR223PreProcessor: Unable to open C:\work\jmeter-scripts-samples\data\transactions.csv 2017/ 12 /29 14:03:24 INFO - jmeter.threads.JMeterThread: Thread is done: Thread Group 1-1 2017/ 12 /29 14:03:24 INFO - jmeter.threads.JMeterThread: Thread finished: Thread Group 1-1 2017/ 12 /29 14:03:24 INFO - jmeter.engine.StandardJMeterEngine: Notifying test listeners of end of test 2017/ 12 /29 14:03:24 INFO - jmeter.services.FileServer: Close: data/ transactionsToProcess . csv 2017 /12/ 29 14 : 03 : 24 INFO - jmeter . gui . util . JMeterMenuBar : setRunning ( false ,* local *)

That’s it! You now understand the importance of Groovy functions in JMeter. We recommend adding JS223 elements in your scripts with Groovy to extend your JMeter functionalities. You can learn more Groovy functions here.

To learn more JMeter, check out our free advanced JMeter academy.

Click here to subscribe to our newsletter.

To try out BlazeMeter, which enhances JMeter abilities, request a demo. Or put your URL in the box below and your test will start in minutes.