In an earlier post I discussed why you might want to use reusable components in Jmeter scripts, in that post I only focused on one possible way of doing that, the Module Controller. For the second part, as promised, I want to discuss the possible uses of the Include Controller.
Why use the Include Controller?
The include controller pretty much does what it states, it allows you to include something external into your test scenario. With controller you can include other JMX files into one single JMX file. So imagine a similar scenario as in the previous post, where you create a JMX specifically for the registration on an application, but then through different channels.
Example: A given application has several ways to communicate to it:
- Consumer webclient
- Backoffice webclient
- Mobile application (communicating via an API)
You can build a set of functional load scenarios for each side of the application, resulting in something like a frontend.jmx, backend.jmx and api.jmx
If you now want to have some full performancetests on the application you can combine these sets with the Include Controller into one big set without making it a huge, unmanageable JMX file.
How does it work?
In the JMX files as mentioned above, instead of a Thread Group you now use a Test Fragment to place your test steps in. If you do happen to use a Thread Group the settings for the thread group from the original JMX will be overridden with the settings from the thread group where the JMX is included.
To avoid confusion, the Test Fragment should be used instead.
Given the existing JMX files you need to use, you create a new project in Jmeter, which will be your master controller. Once you have built the different scenarios you need for your full scale performance test, you consider how these three should work together. Running 3 different JMeter instances, each with its own JMX is an option, however it will make life so much easier if you can actually create a proper flow with the different JMX files.
This Script will be relatively simple and may end up looking something like this:
You can now easily control several scripts, from within one or more thread groups within 1 Jmeter instance while still keeping things maintainable and reusable.
Hi,
I’ve been using Include Controllers in a different use case to your here but have hit a problem and was wondering if you had any ideas.
We work in a continuous deployment environment on a single, large, product with small changes between releases. We have multiple teams each working on different components of this product and thus the product is the sum of multiple teams contributing. Each team is responsible for performance testing their own features and then an additional set of performance tests integrating the teams altogether are run.
We use module controllers to hold ‘keywords’ for different user actions in the application (e.g.: login, create entity, edit entity, save entity, etc.) and tests are built from these modules.
Each team makes changes and thus updates the modules and these modules are kept in small .jmx scripts in a shared Git repo, this way any time any team makes a change to the product (and thus updates the performance modules to represent these changes) every other user can get the most up to date version of the modules without the need to manually edit their test scripts with the changes each time. I have also fully automated the pipeline so off the back of a build the performance tests are run on the newest build on a test environment built up and torn down with no manual user input. This is dependent on the tests being able to get to this central library of modules to get the latest versions of every user action (of which we have about 150 unique ones scripted so far).
The test scripts then use include controllers to call these small external .jmx files.
This is where the problem starts. If we run the test with the modules copied into the parent test script (so it’s one big .jmx) we can easily get to 100-450 users on our single load injector with memory headroom to spare. When we use the multiple include controllers and the small .jmx files the same test with the same load injector gets to about 50 users and runs out of memory on the load injector, runs very slowly and is essentially non-performant.
Jumping into the source code I see
@Override
public Object clone() {
// TODO – fix so that this is only called once per test, instead of at every clone
// Perhaps save previous filename, and only load if it has changed?
this.resolveReplacementSubTree(null);
IncludeController clone = (IncludeController) super.clone();
clone.setIncludePath(this.getIncludePath());
if (this.subtree != null) {
if (this.subtree.size() == 1) {
for (Object o : this.subtree.keySet()) {
this.sub = (TestElement) o;
}
}
clone.subtree = (HashTree)this.subtree.clone();
clone.sub = this.sub==null ? null : (TestElement) this.sub.clone();
}
return clone;
}
It appears that the issue is that each individual user/thread on each loop is cloning the small .jmx files so if we run 100 users with 3 loops we have 300 instances of each module loaded up which I think is causing this memory problem. I can’t find much discussion of this online. Is this something you have come across?
Do you have any suggestions about how to work around this?