Your First Test Plan — A Simple HTTP Request

9 min read

Theory only goes so far. This lesson walks through building a complete JMeter test plan from an empty canvas to a passing run — every click, every field, every result. By the end you will have a working .jmx file and an understanding of the workflow you will use for every test plan in this course.

The target

You will test test.k6.io — a public test server maintained by Grafana Labs specifically for load testing practice. It accepts arbitrary traffic and returns predictable responses without rate-limiting, which makes it ideal for learning.

Building the test plan step by step

Step 1 of 9

Open JMeter

Launch JMeter. An empty test plan appears in the tree with a single root node: 'Test Plan'. This is where everything you build will live.

What the .jmx file looks like

Open first-test.jmx in a text editor. You will see the XML that JMeter generated from your GUI configuration:

<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.6.3">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan"
              testname="Test Plan" enabled="true">
      <stringProp name="TestPlan.comments"></stringProp>
      <boolProp name="TestPlan.functional_mode">false</boolProp>
      <hashTree>
        <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup"
                     testname="Thread Group" enabled="true">
          <stringProp name="ThreadGroup.num_threads">1</stringProp>
          <stringProp name="ThreadGroup.ramp_time">1</stringProp>
          <intProp name="ThreadGroup.loop_count">1</intProp>
          <hashTree>
            <HTTPSamplerProxy guiclass="HttpTestSampleGui"
                              testclass="HTTPSamplerProxy"
                              testname="GET /" enabled="true">
              <stringProp name="HTTPSampler.domain">test.k6.io</stringProp>
              <stringProp name="HTTPSampler.path">/</stringProp>
              <stringProp name="HTTPSampler.method">GET</stringProp>
              <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
              <hashTree/>
            </HTTPSamplerProxy>
          </hashTree>
        </ThreadGroup>
      </hashTree>
    </TestPlan>
  </hashTree>
</jmeterTestPlan>

Every GUI element maps to an XML element. The tree structure in the GUI mirrors the <hashTree> nesting in the XML. testname is the element name you typed in the GUI.

Compare this to an equivalent K6 script:

import http from 'k6/http';
 
export const options = { vus: 1, iterations: 1 };
 
export default function () {
  http.get('https://test.k6.io/');
}

K6 is more concise and readable in source form. JMeter's XML is verbose but self-describing — every property has a name, making the file interpretable without running it. Both approaches are valid; they reflect the tool's design philosophy.

Reading the View Results Tree

When you click a result entry in View Results Tree, three tabs appear:

Sampler Result — the summary:

  • Load time (total response time in ms)
  • Connect time (TCP handshake)
  • Latency (time to first byte)
  • Response code (200, 404, 500, etc.)
  • Response message ("OK", "Not Found")
  • Bytes sent / received

Request — exactly what JMeter sent:

  • Full URL
  • Request headers (including User-Agent, Accept, etc.)
  • Request body (for POST/PUT requests)

Response Data — what the server returned:

  • Response headers
  • Response body (HTML, JSON, XML, etc.)

A green circle next to a result means JMeter considers it a success. A red circle means failure. Without assertions, JMeter considers any response a success — even a 500 error. Adding assertions is how you tell JMeter what "success" actually means for your application.

Running from the command line

GUI mode is for development. Once your test plan is ready, switch to CLI mode for actual load testing:

jmeter -n -t first-test.jmx -l results.jtl
  • -n — non-GUI mode
  • -t first-test.jmx — the test plan file
  • -l results.jtl — the results log file (CSV format)

JMeter prints a summary to the terminal as the test runs:

summary +      9 in 00:00:01 =    6.6/s Avg:   143 Min:    89 Max:   347 Err:     0 (0.00%)
summary =      9 in 00:00:01 =    6.6/s Avg:   143 Min:    89 Max:   347 Err:     0 (0.00%)

After the test, generate an HTML dashboard from the results:

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

Open ./report/index.html in a browser to see response time charts, throughput graphs, and error rates. This is the standard artefact you attach to a CI/CD run.

⚠️ Common mistakes

  • Not clearing results between runs. View Results Tree accumulates all results from every run until you clear it. If you run the test five times without clearing, you see five runs mixed together. Click the broom icon (Clear All) before each run during development. In CLI mode this is not an issue — each run writes to its own .jtl file.
  • Forgetting to save before running. JMeter runs the saved file, not the in-memory GUI state. A change you made two minutes ago is not in effect until you save and run again. Make save → run a reflex: Ctrl+S then Ctrl+R.
  • Using View Results Tree in load tests. This listener stores the full request and response body for every single request in memory. At 100 req/s for 5 minutes (30,000 requests), this will exhaust your heap and crash the test. Use Aggregate Report or Summary Report for load tests — View Results Tree is for debugging individual requests only.

🎯 Practice task

Build and run the test plan described in this lesson, then extend it.

  1. Follow the nine steps above to create first-test.jmx targeting test.k6.io/. Run it with 1 user, 1 loop, and verify the green result in View Results Tree.
  2. Inspect the Sampler Result tab. Note the response time, response code, and bytes received.
  3. Change the Thread Group to 5 users, 5 loops. Save and run. Observe all 25 results in View Results Tree.
  4. Run the same test from CLI mode: jmeter -n -t first-test.jmx -l results.jtl. Confirm the summary prints to the terminal.
  5. Generate the HTML dashboard: jmeter -g results.jtl -o ./report/. Open index.html and find the APDEX score and 90th percentile response time.

Open the generated .jtl file in a text editor and identify the column headers. Find the row with the longest elapsed time.

// tip to track lessons you complete and pick up where you left off across devices.