Load Testing With JMeter (Part 2)

In the previous post on this topic I showed you the basics of doing some things in JMeter. We basically got to the point where you could be productive with it and stopped there. If you were to read that and be done you might be alright. Combining basic knowledge with mild experimentation can yield good results over a long enough period of time.

Sometimes though, you’ll have to get much more complicated than just “requesting a series of pages and graphing the results.” The next two installments in this series are intended to address the more advanced topics. This post concerns abstract concepts like Controllers and Assertions whereas the next (and last) installment will bring everything together and we’ll start building some complex test plans.

This is obviously not an exhaustive list of what JMeter provides, I’ve just tried to distill the official manual down to its most practically useful parts so that we know how to build our more complex plans in the next post.

Contents

Scope and The Effect of Nesting Elements

With JMeter, individual elements can change their behavior depending on where they are in relation to other elements. Most of elements (such as Timers and Assertions) are hierarchical where the other elements that this element applies to is determined by the immediate parent. For instance, if you add a timer to a controller, then the timer is applied to all the samplers that are also descendants of that same parent controller. However if you nest the timer below a particular sampler, it becomes something that runs before only that particular request.

A minority of elements (basically controllers and samplers) are strictly sequential. Meaning their behavior only changes with their position in the tree in the sense that the order in which they’re executed differs. This is as opposed to a Config element where moving it underneath a particular sampler changes what it applies to.

If you’re in doubt as to which category your element falls within, just select a random sampler in your test plan, go to “add” and anything listed there will by definition have to be a hierarchical element. The only exception that I’m aware to that rule would be the “User Defined Variables” config element. No matter where it’s placed in the tree it will always have the same effect. The benefit of the UDV element is that it gives you a single object you can enable/disable/delete from your test plan as opposed to the variables set on the root node (which you can only manage individually).

Functions and Variables

In the last article, I mentioned user variables briefly, almost in passing. All user variables (even “User Defined Variables” mentioned later) are plan-wide values specific to each thread executing them. You can then use these values in any of the various fields in the JMeter UI. Variables have more use than just simple substitution though.

JMeter supports two possible ways of storing arbitrary data: properties and variables. JMeter properties are the equivalent of a global variable in other languages where one thread setting a property will change the value seen by all threads whereas each variable’s value is specific to each thread.

For dynamic values, post-processors (such as XPath Extractor) can store an extracted value from one the result request in a variable for use in any following request. In so doing, each thread in your test plan can be extremely dynamic generating loads for complex scenarios. For example, the JSON Extractor post-processor can log into a REST API, receive a temporary token, and then use the value of that token in subsequent requests. Something that it literally impossible to do with static values.

In the same breath as variables, we have functions. The syntax for calling a function is largely the same as using a variable:

${__functionName(arg1, arg2, arg3 ...)}

Example valid function calls might be:

${__machineIP}
${__RandomString(15,abcdefg,)}
${__time}

You’ll notice that the syntax for calling a function without arguments can be identical to referencing a variable except for the double underscore that precedes the function name in the naming convention. The last function call, for instance could have also been written as ${__time()} or ${__time(,)} with identical effect. It just looks ugly to use unnecessary characters.

JMeter comes with a huge list of predefined functions for virtually every need you could have (including the ability to execute JavaScript from inside JMeter). It’s important to remember that function, as it helps work around issues with JMeter’s variable expressions (useful later) by allowing you to insert ECMA at strategic points.

setUp and tearDown Thread Groups

The idea behind these two thread groups is pretty simple: they carry out the tasks required to prepare the pre-requisites for the test to function (setUp) as well as cleaning up afterwards (tearDown). I won’t spend too much time explaining them since they’re virtually identical to regular thread groups except for this one aspect where setUp and tearDown run sequentially before and then after regular thread groups whereas regular thread groups all execute in parallel (by default).

Logic Controllers

Logic controllers fill the role that control structures in other languages do. For instance, there are If controllers for branching based on variable or function output and ForEach controllers for iterating over a series of similarly named variables (since JMeter doesn’t support arrays).

I won’t go over each and every controller element but briefly here are the one that are, in my opinion, the most important:

  • Simple: This controller is just a container and makes no functional difference to how the test executes. This is useful if you have many test elements and just want to group them together in collapsible boxes so that it’s easier to navigate your test or for new users to see how your test is structured.
  • If: As mentioned earlier, this is used for evaluating the truthiness of a particular expression. Default uses javascript to evaluate the condition but if you select “Interpret Condition as Variable Expression?” the condition must be a JMeter variable or function that returns some version of the word “true.”
  • While: Exactly like in other languages, this executes a loop on the nested elements for as long as the configured condition evaluates to “true.” Currently, only conditions supported are JMeter conditions but you can generally work around that by using the ${__javascript()} function. This is useful for situations such as having a portion of your test pause waiting for a remote condition to be satisfied before proceeding with the test. For instance, the first part of your test may create an object using a REST API and then you insert a While loop that polls the API to see if it’s finished being processed by the server before then using the object in subsequent load tests.
  • Once Only: Causes JMeter to only execute the nested items once per thread no matter how many loops you have configured. Useful for situations such as each thread creating an object in a REST API. In that case you don’t want to continually create new objects, you just want each thread of your test to have its own private object to run subsequent tests with.
  • Random and Random Order: These are two separate but similar controllers useful for inserting a bit of thread randomness. Random Order disregards JMeter’s normal sequential execution of nested elements and executes any nested items randomly. The Random controller on the other hand, randomly executes only one nested item.

Config Elements

Often Samplers, Listeners, Controllers, etc work as expected out of the box. Often though you’ll need to add some sort of specific configuration to one of them that isn’t present on the element’s configuration pane.

Some of the more useful configuration elements:

  • User Defined Variables: Sets new variables as part of the test plan. As mentioned previously, its placement in the tree doesn’t affect anything except readability. Just put it some place you’re going to be able to easily find later.
  • HTTP Cookie Manager: Stores any cookies the server sends your way, similar to a web browser. Alternatively, you could configure the Cookie Manager to disallow cookies at which point it’s functionally identical to having not added a Cookie Manager at all, except now the policy is explicitly defined for anyone looking over the test plan.
  • Counter: Not independently useful but when nested inside of a loop (such as a While loop) you can approximate the foreach (i=0; i<=5; i++) pattern found in most other languages (more closely than the actual ForEach controller mind you). Please note that since the counter needs to be a direct descendant of the loop, the increment of the counter will be part of the loop’s execution and will be the first thing ran (no matter where it is). For instance if your counter is currently at 5 and your condition is ${iter} <= 5 the condition in your while loop will still evaluate to true for 6 because at the time of condition evaluation it is equal to 5 and only becomes 6 once the loop starts. Please bear this in mind to prevent off-by-one errors.

Timers

With JMeter “timer” usually down to some kind of pause. Generally, there are four types of timers you’ll care about:

  • Constant Timer: Most basic timer, only one version of this one. It pauses execution for a predefined amount of time (specified in milliseconds).
  • Random Timers: Several iterations of this timer. This pauses execution for a variable amount of time. The only difference between the different random timers is how “random” is calculated. Random pauses are useful ways to get each thread far out of sync with one another. That has the effect of the rest of the thread group behaving as a group of random users.
  • Throughput Timer: Throttles each thread so that only a certain number of samples are gathered per minute. It can count samples per-thread or for the entire thread group. This is useful if you’re not trying to use JMeter to collect metrics, you just need to generate a certain amount of load while you debug the application. It’s also useful for creating “background work” in one thread group while a second thread group is performing the actual load you’re collecting metrics for.
  • Synchronizing Timer: Sometimes you don’t want to simulate random traffic and you need to ensure all threads are at the same point in their respective loops so that they can be released in unison. For instance, in the previous “background work” example, you may also want to simulate “bursty” demand during your workload so you may have each thread perform the background work then re-sync before starting the loop again so that demand goes up all at once. The alternative would be for each thread to gradually get out of sync as the time taken for each thread’s execution would vary. That’s a useful feature if you’re trying to simulate random background traffic but not load testing during periods of sudden increases in demand.

Post Processors

Post processors take the result of a previous sample operation and extract some sort of operation from it, saving the result in a variable (referred to in this context as the “reference”). It’s a hierachical class of elements, but usually you would only use a post-processor nested underneath the operation you’re extracting the value from.

Some of the more useful post processors:

  • JSON Extractor: Exactly like what its name implies, used for extracting values from JSON data. Useful for load testing REST API’s.
  • XPath Extractor: Used to extract values from a DOM tree in cases such as XML or HTML being returned by the request. Example XPath Query: //*/input[@name="country"]/@value returns the value of the “country” input field somewhere on the page. You can technically use this to parse HTML documents but I’ve noticed it can be finicky about strict XML-conformance and have had more luck with the following extractor.
  • CSS/jQuery Extractor: Used in the same cases that the XPath extractor syntax is, different being that instead of using XPath to extract values, it uses CSS select syntax to find the node of interest and has you specify what attribute to return. For instance, a selector would be: input[name=country] and you would specify value is the attribute to return. Another example would be a selector of button.offscreen which will locate button elements with the class of “offscreen.”
  • Regular Expression Extractor: Just a general purpose post-processor where you provide it a regular expression to break the textual response with along with the number used. Useful as a fall back option and for things like plain text results. Parsing HTML or JSON with regexp is kind of difficult so if that’s what you’re trying to do it would work but it would probably be a lot more work than just using the dedicated extractors listed above.

Example Use of a post-processor. First we create an HTTP Request:

Then we can add a nested CSS extractor underneath it:

After which referring to ${joelsVar} in a later text field will have the value of the “type” attribute or “NaN” if it was unable to locate anything.

Further Reading

This post only covers the most important elements and aspects of Jmeter. I’ve tried to distill things down to just the concepts I’ve found most useful. In all practicality, though, you’re going to need more than just the above. Unfortunately, with JMeter that often means digging through the online manual for something that looks like what you need.

Some useful highlights:

  • JMeter Component Reference: For locating a description of some element you can see in the menu system but can’t quite figure out.
  • JMeter Function List: Same use as the component reference, there are many functions and built-in variables. Too many for any guide outside of the manual to really even try to list.
  • JMeter Best Practices Guidelines: For questions of “should” rather than “how.”

So I hope you found that educational. See you in the third and final part of this series!