Showing posts with label jmeter. Show all posts
Showing posts with label jmeter. Show all posts

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.

JMeter Properties Help, Tips, and Examples

Unlike User Defined Variables in JMeter, that seem to be a hack, Properties seem to be well handled and robust in use.

The first benefit of properties is they can be defined outside of your test plan. This allows you to feed parameters into a test plan. Common methods you can use (but not an all inclusive list) to define properties are

- Define them in a user.properties file which is read in when JMeter starts
- pass them on the command line to JMeter using -Jpropertyname=value
- in your test plan using __setProperty function

Unlike User Defined Variables, there is no separate controller for setting or manipulating Properties, so initially you may pass them over. Don't! You just need to get used to evaluating, computing, and setting them 'in line' with the rest of the test. You can also cheat and put functions in places like comments of test elements. So if you want to say use __setProperty and nothing else,, you can create a simple Test Action Sampler and put the function in the comment field of the sampler.

Properties have the benefit over Variables in that
- their scope is the entire test, not just a local thread
- they can be redefined during the test if needed
- their values can be fed into the test externally
- the _property function allows the use of default values

An example in some of my tests is I need to populate some variables for my simulation externally so they can be flexible and controlled by an external script. How many threads to use, how many loops, etc. However, I do not want to be burdened with defining all these parameters every time the test is ran, only if I want to change them.

The best way to do this is use the __property function with it's default value parameter. __P is a shorthand property function. So the Loop Count Parameter of my Loop Controller is defined as

${__P(p_ptploopcount,1)}

If the property named p_ptploopcount is not defined, the test will loop once, and will not fail to execute because of a missing value in the Loop Controller. I don't have to worry about defining p_ptploopcount before using it either since I used the arguement that assigns a default value of 1 if it hasn't been defined. I can override the default value to be 10 on the command line by doing something like this

jmeter -t testplan.jmx -Jp_ptploopcount=10

This method allows for very flexible test plans that can be scaled up or down without modifying the test plan itself.

You can also pre-populate properties using a user.properties file. The gotcha to watch out for though is if you are using the jmeter GUI, the user.properties file is only loaded when jmeter is launched. So you can not change the values, and simply re-run the test without closing and reopening JMeter.

Make sure you remember to name your properties and variables accordingly so you don't forget how to reference them! Variables can be referenced simply by ${name} where properties must be referenced using the __P or __property function

I name all my properties with a p_ prefix to ensure I remember they are properties, and not user defined variables

Jmeter UDV User Defined Variable Tips and Help

The first of many to come tips for others from what I've learned using JMeter.

JMeter has a convoluted way of dealing what most people would be familar with as 'variables'. JMeter has a controller called UDV - User Defined Variables where one can define a variable and assign it a value. But these seemed to have been tacked onto the product later, and their support is a bit messy.

The only real reference to variables in the documentation is here and it's pretty sparse. Here are some lessons learned

Lesson #1 - UDVs can not reference other variables in their own Controller. While you can create multiple variables in a single UDV controller, you can not reference a variable that is defined in that same controller. Example if you were to create two variables

tmsIP = 10.1.1.10
feedbackURL= ${tmsIP}/code.aspx

You can not define them both in the same UDV, you must create one UDV that defines tmsIP, and a second seperate UDV controller to define feedbackURL.

Lesson #2 - Beware the silent fail. If JMeter sees something it does not recognize, it just treats it like a string. So if you are trying to reference the variable 'Beta' using ${Beta} but fat finger it and type ${Betta} you will not get any errors from JMeter that the variable is unknown, etc. It will happliy pass the entire string ${Betta} along. This is the bane of your syntax world. The way to catch this is to use Debug samplers in your test plan along with View Results Tree. The Debug Sampler will show you the state of all the variables at that momment in the test, making it easier to see which do not appear right.

Lesson #3 - References to variable names (and functions too!) are all case sensative. When your variable does not get matched, it will be passed as the simple string and JMeter will not say a thing about it. be careful!

Lesson #4 - Variables are local only to it's own thread. Therefore they are unsuitable for sharing a common counter, etc between different threads in a thread group.

Lesson #5 - Where to manipulate values in an ongoing test. This is my biggest pet peeve of JMeter, there is no clear place to do simply data manipulation in its own step. For instance, for clarity purposes, you want a step that simply modifies an existing value. The answer is quite crude actually, you just put it anywhere! Including in comment fields! So if you want a step that does not generate any samples - you can create a test sampler, that does nothing for the actual test or result, but in the comment field you can put a function if you wanted. The net result of this is typically instead of organizing tests for readability where data manipulation may be seperate from actions using that data.. you end up putting most things 'inline' where the value is the result of a function using your variables or parameters and you do not save the result into its own variable.

Example, instead of defining another variable to hold the value, you may simply use a function like ${__jexl(${callDuration}*1000)} in the value field of a timer.

Lesson #6 - User Defined Variables are only processed at the start of a thread! This means any UDV elements can not be used to manipulate data as the test progresses. So you can't think of variables as you would in the traditional sense. Think of them as initial values that are local to the thread only. To get new values as the test progresses, you need to either use Properties, which can be modified as a test progresses, Parameters which can be redefined each time the element is hit, or use the result of functions to evaluate expressions that could contain your variables.

Lesson #7 - How to I manipulate/generate new values from variables in JMeter? Something simple like multiplying two values and storing the result? This is where the 'hands off' approach to data manipulation in JMeter is frustrating. Basically JMeter has almost no operator type functions... you need to dump all the work into JEXL, JavaScript, or BeanShell and reference it with the respective function. So if you don't know basic JEXL, JavaScript, or BeanShell, you gotta learn it to do basic stuff. Sucks. But basic operator stuff is pretty simple. Instead of assigning the result to a variable, typically it works best just to put the operation 'in line' where ever it is needed. So if my variable callDuration is in milliseconds and I need a seconds view of it, I could use ${__jexl(${callDuration}*1000)} which allows me to reference the JMeter variable callDuration and multiply it by 1000 and the expression's result will replace the function itself where ever it is located.