August 18, 2020

How to Write JMeter Groovy Functions

Open Source Automation

JMeter and Groovy are often used together. In this blog, we'll cover how to write JMeter functions in Groovy.

Back to top

What Is the Use of Groovy in JMeter?

The Groovy language is used as a scripting language for JMeter. When it comes to improving JMeter’s functionality, Groovy has proven to be a powerful, and yet lightweight, language in terms of performance.

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. 

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.

Back to top

How Do I Run a Groovy Script in JMeter?

Here's how you can run a Groovy script in JMeter.

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)
}

 

Back to top

How Groovy Improves JMeter

We will now present examples where Groovy improves JMeter’s functionality.

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

A screenshot of Groovy in the JSR223 PreProcessor

 

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 + "\n "		  
	  }
}

 

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 << "---------------------------------------------------------------------------------------- \n";
responseFile << "                              " + sample + "\n";
responseFile << "---------------------------------------------------------------------------------------- \n";
//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#">

 

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 

 

Back to top

Using JMeter + Groovy For 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 on Tutorialspoint.

To learn more JMeter, check out our free advanced BlazeMeter University.

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.

This blog was originally published on August 16, 2017 and has since been updated for accuracy and relevance.

START TESTING NOW

Related Resources:

Back to top