Run massively scalable performance tests on web, mobile, and APIs

Request a Demo
Nov. 21st, 2018

How to Create Non-GUI JMeter Tests with JMeter Classes

Apache JMeter™ has two modes of operation: GUI and non-GUI. Typically, the GUI-mode is used to create a script and debug it, and the non-GUI is used for execution. But let's imagine a situation where we don’t have the possibility to use the graphical interface, and the script needs to be created in code. For example, when Linux is installed on our server without a graphical interface. Because JMeter scripts are .jmx files of XML structure, we can write our test in the console using any text editor. In this blog post, we will learn how.

 

To create a JMeter script in non-GUI mode, we will use xml-elements. Each element contains JMeter class names, which implement JMeter components, and a set of properties, which determine component settings. Together, this allows us to create full-fledged scripts.

 

A few tips for using JMeter Classes:

  • If you do not know the exact name of the class you need, use the search on the page. Please note that class names are specified in camelCase.
  • If you want to add a new element as a child to an existing one, then simply add it inside the <hashTree></hashTree> tags of the parent element.  In a case where an element can be a parent too, before closing the <hashTree> tag, add one more </hashTree> tag at the child level (JMeter does this in GUI mode).
  • To improve your JMeter Class skills, I recommend you observe the code of some ready scripts. For example, you can find standard templates at the following address on your computer: ..\apache-jmeter-4.0\bin\templates\

 

Writing Our Script

 

We will start with the Test Plan and Thread group.

 

1. First, we will create an empty script. Use - testclass="TestPlan". This is a standard definition of a test plan, which corresponds to test plan settings in the GUI mode (the one we see every time we create a new script).

 

If you need to change a parameter, find the corresponding entry in the file and make the required changes. For example, if you want thread groups to be executed consecutively, we change the parameter 'Testplan_serialize_threadgroups' to true. This corresponds to setting checkbox 'Run thread groups consecutively' in the test plan GUI form.

 

<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="4.0" jmeter="4.0 r1823414">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
      <stringProp name="TestPlan.comments"></stringProp>
      <boolProp name="TestPlan.functional_mode">false</boolProp>
      <boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
      <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
      <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
        <collectionProp name="Arguments.arguments"/>
      </elementProp>
      <stringProp name="TestPlan.user_define_classpath"></stringProp>
    </TestPlan>
    <hashTree/>
  </hashTree>
</jmeterTestPlan>

 

running jmeter classes in non-gui mode

 

2. Then, let’s add a regular Thread Group in Test Plan. Use -  testclass="ThreadGroup”.

 

<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="4.0" jmeter="4.0 r1823414">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
      <stringProp name="TestPlan.comments"></stringProp>
      <boolProp name="TestPlan.functional_mode">false</boolProp>
      <boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
      <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
      <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
        <collectionProp name="Arguments.arguments"/>
      </elementProp>
      <stringProp name="TestPlan.user_define_classpath"></stringProp>
    </TestPlan>
    <hashTree>
      <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
          <boolProp name="LoopController.continue_forever">false</boolProp>
          <stringProp name="LoopController.loops">1</stringProp>
        </elementProp>
        <stringProp name="ThreadGroup.num_threads">1</stringProp>
        <stringProp name="ThreadGroup.ramp_time">1</stringProp>
        <boolProp name="ThreadGroup.scheduler">false</boolProp>
        <stringProp name="ThreadGroup.duration"></stringProp>
        <stringProp name="ThreadGroup.delay"></stringProp>
      </ThreadGroup>
      <hashTree/>
    </hashTree>
  </hashTree>
</jmeterTestPlan>

 

Please keep in mind that for different types of Thread Groups, different JMeter classes are used (for example - “SetupThreadGroup”, “com.blazemeter.jmeter.threads.concurrency.ConcurrencyThreadGroup”, and so on). Learn about different thread groups from blog posts like this one, this one and this one.

 

As you can see, each component has its own properties in the form of tags <stringProp>, <intProp>, <boolProp>, <elementProp> and <collectionProp>. These parameters define the configuration of our component.

 

  • <boolProp> is used for parameters, such as booleans (true/false), which are checkboxes in GUI mode.
  • <intProp> is used to specify the value for a integer type parameters, which are the fields in which the numbers are expected in GUI mode.
  • <stringProp> is used to specify the value for a string type parameters, which are the fields in which the strings are expected in GUI mode.
  • These tags are nested in the <elementProp> tag, which defines the set of the configuration of a single element of our JMeter component.
  • The set of such <elementProp> tags is nested in the tag <collectionProp>.

 

Let's add a few more components.

 

3. Add an HTTP Request sampler to the regular Thread Group. The sampler will send a request to blazedemo.com. Use -  testclass="HTTPSamplerProxy". Note where the URL is configured in the script.

 

<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="4.0" jmeter="4.0 r1823414">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
      <stringProp name="TestPlan.comments"></stringProp>
      <boolProp name="TestPlan.functional_mode">false</boolProp>
      <boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
      <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
      <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
        <collectionProp name="Arguments.arguments"/>
      </elementProp>
      <stringProp name="TestPlan.user_define_classpath"></stringProp>
    </TestPlan>
    <hashTree>
      <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
          <boolProp name="LoopController.continue_forever">false</boolProp>
          <stringProp name="LoopController.loops">1</stringProp>
        </elementProp>
        <stringProp name="ThreadGroup.num_threads">1</stringProp>
        <stringProp name="ThreadGroup.ramp_time">1</stringProp>
        <boolProp name="ThreadGroup.scheduler">false</boolProp>
        <stringProp name="ThreadGroup.duration"></stringProp>
        <stringProp name="ThreadGroup.delay"></stringProp>
      </ThreadGroup>
      <hashTree>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="HTTP Request" enabled="true">
          <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" enabled="true">
            <collectionProp name="Arguments.arguments"/>
          </elementProp>
          <stringProp name="HTTPSampler.domain"></stringProp>
          <stringProp name="HTTPSampler.port"></stringProp>
          <stringProp name="HTTPSampler.protocol"></stringProp>
          <stringProp name="HTTPSampler.contentEncoding"></stringProp>
          <stringProp name="HTTPSampler.path">http://blazedemo.com</stringProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
          <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
          <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
          <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
          <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
          <stringProp name="HTTPSampler.connect_timeout"></stringProp>
          <stringProp name="HTTPSampler.response_timeout"></stringProp>
        </HTTPSamplerProxy>
        <hashTree/>
      </hashTree>
    </hashTree>
  </hashTree>
</jmeterTestPlan>

 

Hints:

  • If you need to send a POST request instead of a GET, replace "<stringProp name="HTTPSampler.method">GET</stringProp>" string with "<stringProp name="HTTPSampler.method">POST</stringProp>".
  • If you want to turn on the auto-redirect, replace " <boolProp name="HTTPSampler.auto_redirects">false</boolProp>" with " <boolProp name="HTTPSampler.auto_redirects">true</boolProp>".

 

Now that the logic is more understandable, let's go further.

 

4. Now, add a loop controller with an infinite number of iterations in Thread Group (set <boolProp name="LoopController.continue_forever">true</boolProp> and <intProp name="LoopController.loops">-1</intProp>). We’ll move our HTTP Request to the Loop Controller. Add -  testclass="LoopController".

 

Pay attention to the tag <hashTree>. This tag is always present at the beginning and the end of each element. The correct placing of this tag indicates the hierarchy of components in our script.

 

<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="4.0" jmeter="4.0 r1823414">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
      <stringProp name="TestPlan.comments"></stringProp>
      <boolProp name="TestPlan.functional_mode">false</boolProp>
      <boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
      <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
      <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
        <collectionProp name="Arguments.arguments"/>
      </elementProp>
      <stringProp name="TestPlan.user_define_classpath"></stringProp>
    </TestPlan>
    <hashTree>
      <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
          <boolProp name="LoopController.continue_forever">false</boolProp>
           <stringProp name="LoopController.loops">1</stringProp>
        </elementProp>
        <stringProp name="ThreadGroup.num_threads">1</stringProp>
        <stringProp name="ThreadGroup.ramp_time">1</stringProp>
        <boolProp name="ThreadGroup.scheduler">false</boolProp>
        <stringProp name="ThreadGroup.duration"></stringProp>
        <stringProp name="ThreadGroup.delay"></stringProp
      </ThreadGroup>
      <hashTree>
        <LoopController guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
          <boolProp name="LoopController.continue_forever">true</boolProp>
          <intProp name="LoopController.loops">-1</intProp>
        </LoopController>
        <hashTree>
          <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="HTTP Request" enabled="true">
            <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" enabled="true">
              <collectionProp name="Arguments.arguments"/>
            </elementProp>
            <stringProp name="HTTPSampler.domain"></stringProp>
            <stringProp name="HTTPSampler.port"></stringProp>
            <stringProp name="HTTPSampler.protocol"></stringProp>
            <stringProp name="HTTPSampler.contentEncoding"></stringProp>
            <stringProp name="HTTPSampler.path">http://www.blazedemo.com/</stringProp>
            <stringProp name="HTTPSampler.method">GET</stringProp>
            <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
            <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
            <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
            <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
            <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
            <stringProp name="HTTPSampler.connect_timeout"></stringProp>
            <stringProp name="HTTPSampler.response_timeout"></stringProp>
          </HTTPSamplerProxy>
          <hashTree/>
        </hashTree>
      </hashTree>
    </hashTree>
  </hashTree>
</jmeterTestPlan>

 

5. Now, we will increase the number of threads (set <stringProp name="ThreadGroup.num_threads">10</stringProp>) and ramp-up period (set <stringProp name="ThreadGroup.ramp_time">5</stringProp>), and then we’ll set the duration of our test in Thread Group (set <boolProp name="ThreadGroup.scheduler">true</boolProp> and <stringProp name="ThreadGroup.duration">30</stringProp>).

 

Pay attention to the tag <hashTree>, this tag is always present at the beginning and the end of each element. The correct placing of this tag indicates the hierarchy of components in our script.

 

<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="4.0" jmeter="4.0 r1823414">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
      <stringProp name="TestPlan.comments"></stringProp>
      <boolProp name="TestPlan.functional_mode">false</boolProp>
      <boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
      <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
      <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
        <collectionProp name="Arguments.arguments"/>
      </elementProp>
      <stringProp name="TestPlan.user_define_classpath"></stringProp>
    </TestPlan>
    <hashTree>
      <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
          <boolProp name="LoopController.continue_forever">false</boolProp>
          <stringProp name="LoopController.loops">1</stringProp>
        </elementProp>
        <stringProp name="ThreadGroup.num_threads">10</stringProp>
        <stringProp name="ThreadGroup.ramp_time">5</stringProp>
        <boolProp name="ThreadGroup.scheduler">true</boolProp>
        <stringProp name="ThreadGroup.duration">30</stringProp>
        <stringProp name="ThreadGroup.delay"></stringProp>
      </ThreadGroup>
      <hashTree>
        <LoopController guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
          <boolProp name="LoopController.continue_forever">true</boolProp>
          <intProp name="LoopController.loops">-1</intProp>
        </LoopController>
        <hashTree>
          <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="HTTP Request" enabled="true">
            <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" enabled="true">
              <collectionProp name="Arguments.arguments"/>
            </elementProp>
            <stringProp name="HTTPSampler.domain"></stringProp>
            <stringProp name="HTTPSampler.port"></stringProp>
            <stringProp name="HTTPSampler.protocol"></stringProp>
            <stringProp name="HTTPSampler.contentEncoding"></stringProp>
            <stringProp name="HTTPSampler.path">https://www.blazedemo.com/</stringProp>
            <stringProp name="HTTPSampler.method">GET</stringProp>
            <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
            <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
            <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
            <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
            <stringProp name="HTTPSampler.embedded_url_re"></stringProp>
            <stringProp name="HTTPSampler.connect_timeout"></stringProp>
            <stringProp name="HTTPSampler.response_timeout"></stringProp>
          </HTTPSamplerProxy>
          <hashTree/>
        </hashTree>
      </hashTree>
    </hashTree>
  </hashTree>
</jmeterTestPlan>

 

This is what the script we created would look like in GUI mode:

 

writing a jmeter script in non-gui mode

 

That's it, our script is ready! Now just save your script from the text editor as a .jmx file.

 

Running Our Script

 

Now let's run our script in the non-GUI. To do this, run the following command in the console:

 

 jmeter -t /pathToScript/nameOfYourScript.jmx -n -l /pathToScript/report.jtl

 

After running our script, we should get a JTL file in the specified folder (in our case, pathToscript). Now let’s create a JMeter report in a separate folder near our .jtl file:

 

jmeter -g /pathToScript/report.jtl -o  /pathToScript/report

 

Now we have not only a script, but also a report.

 

jmeter load testing, non-gui, script creation

 

To create more complex scripts, you will need to use more classes. See the full list and description of all JMeter classes here.

 

Editing Our Script

 

If you need to edit your scripts, I recommend editing in non-GUI mode, even if you have access to the GUI mode. If you need to edit a class, change titles, add a comment, etc., doing this via the GUI will take much more time.

 

Instead, just open your script as a text file, and use the search or search + auto-replace for the desired text. This will reduce editing time, and significantly reduce the possibility of missing something.

 

As an example - suppose you have a complex script in which the same variable is used in many places. If you need to change this variable, or change its name in all places, then using the GUI you will have to check the entire script in great detail. However, in non-GUI it will not take more than one minute, and is less error-prone.

 

That’s it! You now know how to quickly create JMeter scripts and reports and how to edit already created scripts  in non-GUI mode.

 

Now, you can upload your JMX file to BlazeMeter, where you will be able to scale it, share reports and run long, maintenance-free, endurance tests.

 

To try out BlazeMeter, put your URL in the box below, and your test will start in minutes. Or, request a free demo.

     
arrow Please enter a valid URL

Interested in writing for our Blog? Send us a pitch!