Export Test Tree from JMeter to Text
Hi, Habr!
I work on a large integration project (IBM WAS, WebSphere MQ, Oracle) and wrap our bloody enterprise with a web of functional tests in JMeter, which spins on a test bench and wakes up at the call of Jenkins after the deployment of the new build. As the number of tests increased, I encountered the problem of keeping test documentation up to date.
The test tree itself in JMeter is essentially a document — the trades break down the functionality into logical chunks, inside the trad controllers contain tests, and each sampler inside the controller is a separate step. The hierarchy of objects is clearly numbered, with the exception of service pieces like assortments, timers, and other less interesting things from a business logic point of view.
The result is a fairly neat picture:

However, not every manager is ready to run JMeter in order to view the state of affairs in the field of QA. Historically, all project documentation is maintained in Confluence.
I was not ready to manually copy-paste the description of test cases to the Confluence page after developing them in JMeter. Desperate googles didn’t work - I didn’t find a ready and easy solution for exporting a tree of objects from JMeter into the text ( if you do, write about it in the comments, please, and I’ll sprinkle it with ashes from the achivka "I know how to google" ).
Looking into the insides of the JMX file (the standard extension of the JMeter test plan), I discovered that all the objects that interest me are marked with the testname attribute :
<AuthManagerguiclass="AuthPanel"testclass="AuthManager"testname="1.4.2 Авторизоваться на портале"enabled="true"><collectionPropname="AuthManager.auth_list"><elementPropname=""elementType="Authorization"><stringPropname="Authorization.url">http://${ipKvp}:${portKvp}/TKVPImportTemporary</stringProp><stringPropname="Authorization.username">${userKvp}</stringProp><stringPropname="Authorization.password">${passKvp}</stringProp><stringPropname="Authorization.domain">${domainKvp}</stringProp><stringPropname="Authorization.realm"></stringProp></elementProp></collectionProp><boolPropname="AuthManager.clearEachIteration">true</boolProp></AuthManager>
The only thing left to do is to write a parser that:
- Get the desired text with the description of the step \ test \ group from the JMX file
- Throws out lines describing uninteresting objects (completed, timers, etc.)
- Write everything in order to a file so that the document update includes one lonely copy-paste
Regular expression successfully coped with clause 1:
(? <= testname = \ ") (. *) (? = \")
From using the xpath-selector I was saved by a reflex not to use the xpath acquired in the process of writing selectors for Selenium tests.
Since I did not number the service objects in the tree, point 2 was able to be implemented without problems in the loop, in which:
- I take out the first character of the string
- lead to int
- in case of success I write the line in the list
- otherwise ignore
try (BufferedReader br = new BufferedReader(new FileReader(JMX_FILE))) { String line; while ((line = br.readLine()) != null) { Matcher m1 = p.matcher(line); if (m1.find()) { try { Integer.parseInt(m1.group().substring(0, 1)); matchd.add(m1.group()); } catch (NumberFormatException e) { System.out.println(m1.group().substring(0, 1) + ": excluding non-number string"); } } } }
And since the file is processed in succession from top to bottom + the numbering of the objects in the tree is subject to a clear logic, it was not necessary to invent anything terrible for clause 3:
FileWriter writer = null;
try {
writer = new FileWriter(RESULT_FILE);
for (String str : matchd) {
writer.write(str + "\n");
}
} finally {
if (writer != null) {
writer.close();
}
}
The final result fit into one small (~ 50 lines) class:
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
publicclassApp{
privatestaticfinal String SAMPLER_NAME_REGEXP = "(?<=testname=\")(.*)(?=\" )";
privatestaticfinal File JMX_FILE = new File("C:\\temp\\Test-plan.jmx");
privatestaticfinal File RESULT_FILE = new File("C:\\temp\\output.txt");
publicstaticvoidmain(String[] args)throws IOException {
Pattern p = Pattern.compile(SAMPLER_NAME_REGEXP);
List<String> matchd = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new FileReader(JMX_FILE))) {
String line;
while ((line = br.readLine()) != null) {
Matcher m1 = p.matcher(line);
if (m1.find()) {
try {
Integer.parseInt(m1.group().substring(0, 1));
matchd.add(m1.group());
} catch (NumberFormatException e) {
System.out.println(m1.group().substring(0, 1) + ": excluding non-number string");
}
}
}
}
if (RESULT_FILE.delete()) {
System.out.println("Deleting previous result file");
} else {
System.out.println("Creating new result file");
}
FileWriter writer = null;
try {
writer = new FileWriter(RESULT_FILE);
for (String str : matchd) {
writer.write(str + "\n");
}
} finally {
if (writer != null) {
writer.close();
}
}
}
}
As an experiment, I tried to integrate this code directly into the JMeter test plan, but I ran into problems of misunderstanding generics and imports, and so far decided to be satisfied with the call of the obtained exporter of the tree in IDEA.
Take care of your time. And thank you for your attention.
