What Is Apache JMeter?

Apache JMeter is an open-source, Java-based application designed for load testing and measuring the performance of web applications. Originally created for testing web applications, JMeter has expanded to cover a wide range of protocols including HTTP, HTTPS, SOAP, REST, FTP, JDBC, LDAP, JMS, and SMTP.

JMeter is one of the most widely used performance testing tools in the industry. Its popularity stems from being free, extensible through plugins, and having a large community. If you work in QA, you will almost certainly encounter JMeter at some point in your career.

JMeter Architecture

JMeter uses a tree-based structure for organizing test plans. Understanding the core components is essential before you create your first test.

graph TD TP[Test Plan] --> TG1[Thread Group 1] TP --> TG2[Thread Group 2] TG1 --> S1[HTTP Sampler: Login] TG1 --> S2[HTTP Sampler: Browse Products] TG1 --> S3[HTTP Sampler: Add to Cart] S1 --> A1[Response Assertion] S1 --> PP1[Regular Expression Extractor] TG1 --> T1[Constant Timer] TG1 --> L1[View Results Tree] TG1 --> L2[Summary Report] TG1 --> CE1[HTTP Cookie Manager] TG1 --> CE2[CSV Data Set Config]

Test Plan

The Test Plan is the root element. It contains all the elements of your test. A test plan defines what to test and how to go about it. You can think of it as a container for the entire load test scenario.

Thread Groups

A Thread Group is the entry point for your test. It controls:

  • Number of Threads (users): How many virtual users will execute the test simultaneously
  • Ramp-Up Period: How long JMeter takes to start all threads. A ramp-up of 60 seconds with 100 threads means JMeter starts roughly 1.67 users per second
  • Loop Count: How many times each thread executes the test plan. Set to “Infinite” for duration-based tests
  • Duration: Maximum time the test runs (useful with infinite loops)

Samplers

Samplers tell JMeter to send requests to a server. The most common sampler is the HTTP Request Sampler, which sends HTTP/HTTPS requests. Other samplers include JDBC Request (databases), FTP Request, and SMTP Sampler (email).

Key HTTP Request Sampler fields:

  • Protocol: HTTP or HTTPS
  • Server Name or IP: The target server
  • Port Number: Usually 80 (HTTP) or 443 (HTTPS)
  • Method: GET, POST, PUT, DELETE, etc.
  • Path: The endpoint path (e.g., /api/users)
  • Body Data: Request body for POST/PUT requests

Listeners

Listeners collect and display test results. Common listeners include:

ListenerPurpose
View Results TreeDetailed view of each request/response (debugging only)
Summary ReportAggregated statistics table
Aggregate ReportStatistics with percentiles
Graph ResultsVisual graph of response times
Simple Data WriterSaves results to a file for external analysis

Important: View Results Tree consumes significant memory. Disable it during actual load tests and only use it for debugging with a few threads.

Assertions

Assertions verify that responses meet expected criteria. If an assertion fails, JMeter marks the sampler as failed.

  • Response Assertion: Checks response body, headers, or status code
  • Duration Assertion: Fails if response time exceeds a threshold
  • Size Assertion: Validates response size
  • JSON Assertion: Validates JSON response content
  • XPath Assertion: Validates XML response content

Timers

Timers add delays between requests to simulate realistic user behavior. Without timers, JMeter sends requests as fast as possible, which is unrealistic.

  • Constant Timer: Fixed delay between requests
  • Gaussian Random Timer: Random delay with normal distribution
  • Uniform Random Timer: Random delay within a range

Config Elements

Config Elements set up defaults and variables for samplers:

  • HTTP Cookie Manager: Handles cookies automatically (essential for session-based apps)
  • HTTP Header Manager: Adds headers to all requests
  • CSV Data Set Config: Reads test data from CSV files for parameterization
  • HTTP Request Defaults: Sets default values shared across multiple HTTP samplers

Recording HTTP Requests

JMeter includes a Test Script Recorder (formerly HTTP Proxy Server) that captures browser traffic and converts it into JMeter samplers. This is the fastest way to create a realistic test scenario.

Steps to record:

  1. Add a Thread Group to your Test Plan
  2. Add HTTP(S) Test Script Recorder under the Test Plan
  3. Set the port (default: 8888)
  4. Configure your browser to use localhost:8888 as its proxy
  5. Click Start on the recorder
  6. Navigate through your application in the browser
  7. Stop the recorder — JMeter creates samplers for each captured request

After recording, clean up the script by removing unnecessary requests (static assets, analytics calls) and add parameterization for dynamic values.

Parameterization

Parameterization replaces hard-coded values with variables so each virtual user can use different data. The most common approach uses CSV Data Set Config.

Create a CSV file (users.csv):

username,password
user1,pass123
user2,pass456
user3,pass789

Add a CSV Data Set Config element with:

  • Filename: Path to your CSV file
  • Variable Names: username,password
  • Delimiter: ,
  • Recycle on EOF: True (restart from beginning when file ends)
  • Sharing Mode: All threads (each thread reads the next line)

Reference variables in samplers using ${username} and ${password}.

Correlation

Correlation is extracting dynamic values from server responses and using them in subsequent requests. This is critical for applications that use session tokens, CSRF tokens, or dynamic IDs.

Use Regular Expression Extractor or JSON Extractor as a post-processor on the sampler that returns the dynamic value:

  • Reference Name: Variable name (e.g., sessionToken)
  • Regular Expression: Pattern to match (e.g., "token":"(.+?)")
  • Template: $1$ (first capture group)
  • Match No.: 1 (first match)

Then use ${sessionToken} in subsequent requests.

Running JMeter from Command Line

For actual load tests, always use the command-line (non-GUI) mode. The GUI consumes too many resources and skews results.

jmeter -n -t test_plan.jmx -l results.jtl -e -o report_folder

Flags:

  • -n — Non-GUI mode
  • -t — Test plan file
  • -l — Results log file
  • -e -o — Generate HTML report after test

Exercise: Load Test a REST API with JMeter

Create a JMeter test plan that simulates 50 users browsing a bookstore API over 5 minutes.

Scenario

You are testing a REST API for an online bookstore with these endpoints:

EndpointMethodDescription
/api/booksGETList all books
/api/books/{id}GETGet book details
/api/auth/loginPOSTAuthenticate user
/api/cartPOSTAdd book to cart

Requirements

  1. Create a Thread Group with 50 users, 120-second ramp-up, running for 5 minutes
  2. Add HTTP Request Defaults with the server name
  3. Add HTTP Cookie Manager for session handling
  4. Create HTTP Samplers for each endpoint
  5. Parameterize user credentials from a CSV file
  6. Correlate the auth token from the login response
  7. Add Response Assertions to validate status codes
  8. Add a Constant Timer (1-3 seconds) between requests
  9. Add Summary Report and Aggregate Report listeners
  10. Run in non-GUI mode and generate an HTML report
Hint: Test Plan Structure

Your test plan tree should look like:

Test Plan
├── HTTP Request Defaults (server: api.bookstore.example.com)
├── HTTP Cookie Manager
├── CSV Data Set Config (users.csv)
├── Thread Group (50 users, 120s ramp-up, duration: 300s)
│   ├── HTTP Request: Login (POST /api/auth/login)
│   │   ├── JSON Extractor (token from response)
│   │   └── Response Assertion (status = 200)
│   ├── HTTP Header Manager (Authorization: Bearer ${token})
│   ├── Constant Timer (2000ms)
│   ├── HTTP Request: List Books (GET /api/books)
│   │   └── JSON Extractor (bookId from response)
│   ├── Constant Timer (2000ms)
│   ├── HTTP Request: Book Details (GET /api/books/${bookId})
│   │   └── Response Assertion (status = 200)
│   ├── Constant Timer (1000ms)
│   ├── HTTP Request: Add to Cart (POST /api/cart)
│   │   └── Response Assertion (status = 201)
│   ├── Summary Report
│   └── Aggregate Report
Solution: Key Configuration Details

CSV Data Set Config:

Filename: users.csv
Variable Names: username,password
Delimiter: ,
Recycle on EOF: True

Login Request Body:

{
  "username": "${username}",
  "password": "${password}"
}

JSON Extractor on Login Response:

Reference Name: token
JSON Path: $.token
Match No.: 1
Default Value: TOKEN_NOT_FOUND

HTTP Header Manager:

Authorization: Bearer ${token}

JSON Extractor on List Books:

Reference Name: bookId
JSON Path: $.books[0].id
Match No.: 0 (random match)

Results Analysis — What to Look For:

  • Average Response Time: Should be under your SLA (e.g., < 500ms)
  • Error Rate: Should be 0% under normal load
  • Throughput: Requests per second the server can handle
  • 90th Percentile: 90% of requests complete within this time
  • If errors spike during ramp-up: Server may struggle with concurrent connections
  • If response times increase linearly with users: Server is reaching capacity

Command to run:

jmeter -n -t bookstore_test.jmx -l results.jtl -e -o ./report

Open report/index.html to view the interactive HTML dashboard with charts for response times, throughput, and error rates over time.

Pro Tips

  • Distributed Testing: For large-scale tests, use JMeter’s distributed mode with multiple slave machines. One controller sends the test plan to multiple load generators.
  • JMeter Plugins Manager: Install the Plugins Manager (jmeter-plugins.org) for additional listeners like the Transactions per Second graph and the Ultimate Thread Group for complex load profiles.
  • BeanShell vs JSR223: Always use JSR223 + Groovy for scripting instead of BeanShell. Groovy compiles to bytecode and is significantly faster under load.
  • Think Time: Real users pause between actions. Add timers with randomized delays (Gaussian Random Timer with 2000ms deviation and 1000ms offset) for realistic simulation.
  • Assertions at Scale: Disable View Results Tree during load tests. Use only Summary Report or write results to a JTL file for post-test analysis.