Wednesday, October 15, 2008

JMeter Variables vs. Properties. vs. Parameters

One of JMeter's most twisted areas to get accustomed to is the general concept of 'variables'.

There are four basic types of value holders most people would refer to as 'variables' in JMeter

- User Defined Variables (UDV)
- Properties
- User Parameters
- Sampler Response

Many things act on the Sampler Response, which is the data set returned from a sampler, but that one is a bit out side the notion of variables we are talking about here.

The main differences between UDV, Properties, and User Parameters are when the values are set, their scope, and when they can be updated.

UDVs are the most static of the bunch. UDVs are defined in a UDV Config Element. UDV elements are evaluated at the start of a test plan and not updated again during the run of the test. So putting a UDV in a loop controller is not going to re-evaluate the variable each pass of the loop. A UDVs value is also only relative to it own thread. So they can not be used to share the same result between threads, but they can be used as local data holder where each thread may have a different value. I use them for better readability in my scripts for initial setup values (test server IP, a username, etc) but they generally are of limited use beyond that due to the startup-only evaluation of the UDV elements.
UDVs are referenced by ${name}

Properties are the most general data holder in JMeter. There is also the distinction between system properties and user properties. I'll defer you to the JMeter documentation to look into system properties. I haven't had a need for them yet. Unlike UDV which are defined in a Configuration Element, properties are defined
- in a .properties file loaded at JMeter startup.
- by the __setProperty function
- by the command line option -Jpropertyname=value when starting JMeter

This exposure to taking input from outside of JMeter makes properties especially valuable. Properties also have a scope of the entire Test Plan, so you can share values between threads using Properties. Using __setProperty you can overwrite the existing value of a property as well to update some running value if needed.
I use properties to fill in test plan values, and use the default value argument to ensure if the property isn't defined, the test will still execute. Example, to fill in the UDV used for the server address in my test plan, I define the value to be:
${__P(p_tmsIP,10.1.2.183)}
If p_tmsIP is not defined in the .properties files or on the command line, 10.1.2.183 is used

When defining custom properties and I want to load them easily, I use the user.properties file. WARNING - this file is only read on JMeter startup! So if you are using the GUI and leave JMeter open, changing the file once JMeter is opened will not change the values JMeter uses.

User Parameters are a special type of user variable that have two cool features. First, they allow you to define a variable that has a different value per thread, and second, they allow you to define the variable's value to be updated either each time its referenced, or once each time the parent element is passed in the test plan. The first functionality allows you to define a variable and a list of values, each thread will take the next available value defined for the variable. You define multiple values by adding 'users' which adds a new column. I haven't had a need for this yet. The User Parameter is referenced just like a UDV: ${name}

The second notion of when the variable is evaluated is very valuable. If the 'Update Once Per Iteration' checkbox is left unchecked, the expression in the value definition of the variable will be re-evaluated each time the variable is used. So if you have a variable that needs to be evaluated each time its used.. say it includes a time function, that would be very helpful.
Where I have found use in User Parameters is to have the Update Once checkbox marked, this means the value expression will be updated only when the element is passed in the test plan, and the value remains the same until the next pass. This is very valuable in loops. It allows you to evaluate a variable at the start of the loop, maintain the value through, and get a new value on the next loop iteration.

An Example is below. I have a loop that runs a series of samplers that are related in they should use the same variable logid, but I need logid to be unique for each pass through the loop. Each time the loop runs, a new data set should be used. The test plan looks like this:


In this test, the variable logid is defined as $__time(HMS)} in the User Parameter element. This allows me to generate a pretty simple, unique Integer that is refreshed each time the loop is executed, but remain constant through the 3 samplers. This also allows this same block of code to be used by multiple threads and each executed loop will have a unique logid.
Mastering how to use the User Parameter Element has been key to building scripts with loops that are intended to run with multiple threads.

10 comments:

kaustubh said...

Very good write up about JMeter variables. Exactly what I was looking for!

dsinfo said...

Can the User parameter be used to update the value of a variable for each iteration in a single thread when you are not using a function which returns a different value each time or reading from a file using CSVRead or StringFromFile?

Steve said...

The User Parameter will be re-evaluated each time the thread group is restarted. Whatever you put in there, will be evaluated at that time.

dsinfo said...

Do you know if there is any way I can specify a range of values for a set of variables inside a loop or ForEach controller within a single thread and have each loop iteration pick up a different set of values each time? I tried using User Parameters but it gives me the first set of values each time, probably because I have only one thread. I don't want to use CSVRead or CSV Data set.
Thanks and appreciate the quick response to my first post.

Steve said...

You would need to use a property, as that is the only element that can be re-evaluated within a single thread pass. What you make that property read from or defined by is up to you, but a CSV set is probably the best way if its data you are reading data in externally. The JMeter mailing list may also be of help, as it is very active.

dsinfo said...

Other than defining a property in the User Parameters and setting the value to "${__CSVRead(file-to-read-from,0)}${__CSVRead(file-to-read-from,next())}" I can't think of any other way to update the value for the next iteration. Instead of using CSVRead if I specify multiple values for that property, it only reads the first value each iteration. That's why I asked if there is a way to do it without using CSVRead.
I already posted this question to the JMeter mailing list, but I haven't heard any response yet.

Thank you for responding.

Steve said...

property and User Parameters are different things.

You can define and evaluate a property at any time.. This is why they are different. That is the only option you have for updating a value in the middle of a test pass. Use the property function to set it's value to something. You can do so in virtually any field of a test element. JMeter does not have a separate element for just updating properties. So you must do it elsewhere, like the comment field of a test component or something.

dsinfo said...

Are you referring to the setProperty function? How can I use that to say set var1=val1 in 1st iteration, var1=val2 in 2nd iteration and so on where some sampler in the loop is referencing ${var1}. Where would I call it? I can't put it in the sampler because then var1 would always be set to the same value in each iteration.

Hari said...

I think it is worth adding that internally, there are only 3 types:
- System properties
- JMeter properties
- JMeter variables

Note also that "Debug Sampler" lists exactly these 3 types.
- System properties are basically, the Java properties coming from java.lang.System. There is no special syntax to access them, but JMeter properties are initialized from them, so system property values should be accessible like JMeter Properties, unless they have been updated or overridden later.
- JMeter properties come in through jmeter.properties, user.properties or -J command-line options. These can be accessed using the ${__P()} syntax. Can be used to parameterize most elements where you can enter data.
- Variables are defined and manipulated using various config elements such as TestPlan, User Defined Variables, User Parameters and CSV Data Set Config. These can be accessed using ${} syntax. These typically can't be used to parameterize config elements, because they are evaluated too soon (and not re-evaluated for each loop). Each thread always gets a separate copy of these variables, so you can't use them to share data.

Alan said...

When defining a JMeter variable in the UDV, is there any way to force it to use a certain data type ?

i.e. I am using a variable SUM that sums up different values, but the problem is that it in JMeter uses int (or at least i think it does), so if my value goes over 2,147,483,647 i start getting negative values.

Is there any way to force it to use Long as data type instead ?

Thanks