DEV Community

Cover image for Performance Testing Series — Part 1: Why Functional Testing Isn't Enough & Your First JMeter Load Test
Faizal
Faizal

Posted on

Performance Testing Series — Part 1: Why Functional Testing Isn't Enough & Your First JMeter Load Test

Performance Testing Series — Part 1: Why Functional Testing Isn't Enough & Your First JMeter Load Test

"It passed every test case. Then 200 users logged in at once — and it fell over."

I've shipped features that sailed through functional QA. Every test case green. Every acceptance criterion met.

And then they hit production traffic and buckled.

Not because the logic was wrong. Because nobody asked the one question functional testing never asks:

"What happens when more than one person uses this at the same time?"

That's the gap this series fills.

By the end, we'll go from zero to a fully automated performance test suite — running in CI/CD, gating builds on real thresholds, not vibes.

But first — let's understand why this discipline exists at all.


🎯 Functional Testing vs. Performance Testing

Here's the divide, in one line:

Functional testing asks: Does it work?
Performance testing asks: Does it work when it matters?

A login API that returns the right token for one request can still:

  • Time out under 50 concurrent logins
  • Return correct data — but in 8 seconds instead of 200ms
  • Work fine for 100 users, then throw 500 errors at 101
  • Pass every functional check while quietly leaking memory request after request

None of that shows up in a normal test case. You need a fundamentally different kind of testing to catch it.


🚨 Why This Gets Skipped So Often

In most teams I've worked with, performance testing happens after something breaks in production — not before.

The usual reasons:

  • "We'll do it before launch" (launch happens, it doesn't)
  • Nobody owns it — devs assume QA does it, QA assumes devs do it
  • It's seen as a specialist skill, not a core QA competency
  • Teams don't know where to start

That last one is what this series fixes. No prior performance testing experience needed.


🛠️ Enter JMeter

Apache JMeter is a free, open-source tool built specifically for load and performance testing. It can simulate hundreds (or thousands) of concurrent users hitting your API, and tell you exactly how your system behaves under that load.

Why JMeter, specifically:

  • Free and open-source — no licensing cost
  • No-code GUI for building tests, but fully scriptable for CI/CD
  • Protocol-agnostic — HTTP, REST, SOAP, databases, and more
  • Industry standard — most QA teams already expect it on a resume
  • Pairs cleanly with GitHub Actions for automated pipeline runs (we'll get there by Part 8)

⚙️ Installing JMeter

You need Java installed first (JMeter runs on the JVM).

Step 1 — Check Java

java -version
Enter fullscreen mode Exit fullscreen mode

You need Java 8 or higher. If it's missing, install a JDK (Java 17 or 21 LTS recommended).

Step 2 — Download JMeter

Grab the latest binary from the official Apache JMeter site, then extract it.

Step 3 — Launch JMeter

cd apache-jmeter-5.x/bin
./jmeter.sh      # macOS/Linux
jmeter.bat        # Windows
Enter fullscreen mode Exit fullscreen mode

You should see the JMeter GUI open — a mostly empty Test Plan tree on the left.

Important note for later: the GUI is for building and debugging tests only. Real load tests run from the command line (we'll cover that properly in Part 8). For now, GUI is exactly where we want to be.


🌐 The App We'll Test Throughout This Series

Instead of a fictional app, we're using a live, public REST API: ReqRes.

Why this one:

  • Realistic JSON responses with pagination
  • Simulates a real user-management flow: list users, get a single user, login
  • Requires an API key — which actually makes this a better learning example, since most real-world APIs you'll load test in your job are authenticated too

Across this series we'll simulate a believable journey: list users → fetch a single user → simulate login — and load test each of these the way you would a real production API.

Quick setup — grab a free API key

ReqRes now requires an x-api-key header on every /api/* request. This takes under a minute:

  1. Go to reqres.in/signup and create a free account
  2. Grab your API key from the dashboard
  3. Keep it handy — we'll add it to JMeter in the next section

This is a good thing, not a hurdle — it means our very first test plan will already include the kind of header management you'll need for almost every real API you test on the job.


🧪 Building Your First Test Plan

Let's build the simplest possible load test: hit the ReqRes "list users" endpoint with multiple concurrent users.

Step 1 — Add a Thread Group

Right-click Test PlanAddThreads (Users)Thread Group

Configure it:

Number of Threads (users): 10
Ramp-Up Period (seconds): 5
Loop Count: 1
Enter fullscreen mode Exit fullscreen mode

This means: 10 virtual users will start hitting the API, staggered over 5 seconds, each firing the request once.

Step 2 — Add an HTTP Header Manager (for the API key)

Right-click the Thread GroupAddConfig ElementHTTP Header Manager

Add one header:

Name: x-api-key
Value: YOUR_API_KEY
Enter fullscreen mode Exit fullscreen mode

This header gets attached to every request in this Thread Group automatically — you won't need to repeat it per sampler.

Step 3 — Add an HTTP Request Sampler

Right-click the Thread GroupAddSamplerHTTP Request

Configure it:

Protocol: https
Server Name: reqres.in
Path: /api/users?page=2
Method: GET
Enter fullscreen mode Exit fullscreen mode

Step 4 — Add a Listener to See Results

Right-click the Thread GroupAddListenerView Results Tree

This lets you inspect each individual request/response while you're building and debugging — exactly what it's for.

Step 5 — Run It

Click the green Start button (or Ctrl+R).

Watch the View Results Tree populate. Click any request to see the full response — you should see ReqRes's paginated user JSON come back, with a green checkmark if it succeeded.


📊 What You're Actually Looking At

Once the run finishes, every request in the tree shows you:

Sample Time: how long this specific request took
Response Code: 200, 404, 500, etc.
Response Data: the actual JSON returned
Load Time / Latency: time breakdown
Enter fullscreen mode Exit fullscreen mode

This is the raw material performance testing is built on. In Part 6, we'll learn to read aggregated versions of these numbers — throughput, percentiles, error rate — across hundreds or thousands of requests, not just ten.

For now, the goal is simpler: you just ran your first real load test, against a live API, and you can see exactly what came back. That's the foundation everything else in this series builds on.


🔴 A Quick Reality Check

Ten users hitting a stable public API for one loop isn't going to break anything — and that's intentional. This part is about mechanics: Thread Groups, Samplers, Listeners, and the GUI workflow.

Starting in Part 5, we'll deliberately push load far higher — ramp-up patterns, spike tests, soak tests — to actually find breaking points. But you don't push for failure before you understand the tool. That comes next.


🚀 What's Coming in This Series

Part 1 — JMeter Setup & Your First Load Test                  ← You are here
Part 2 — Building Realistic User Journeys: Samplers & Listeners In Depth
Part 3 — Parameterization & Correlation: Making Tests Dynamic
Part 4 — Assertions & Response Validation
Part 5 — Load Patterns: Ramp-Up, Spike, Soak & Stress Testing
Part 6 — Reading the Numbers: Throughput, Latency & Percentiles
Part 7 — Distributed & Realistic Load Simulation
Part 8 — Automating Performance Tests in CI/CD with GitHub Actions
Enter fullscreen mode Exit fullscreen mode

By Part 8, you'll have a performance test suite that runs automatically on every build, with pass/fail thresholds gating your pipeline — not a manual GUI exercise you remember to run occasionally.


🎯 Who Is This Series For?

  • QA engineers who've only ever done functional/UI testing
  • Automation engineers who want a third pillar alongside functional and API automation
  • Developers who want to understand what their team's load tests are actually measuring
  • Anyone who's been told "we should probably load test this" and didn't know where to start

No prior performance testing experience required.


🔖 Before You Go

Functional testing tells you a feature works.

Performance testing tells you it'll keep working when real users show up — not one at a time, but all at once.

That gap is exactly where production incidents live. And it's a gap most QA engineers never get formal training to close.

This series is that training.


Follow me so you don't miss Part 2 — where we go beyond a single GET request and start building realistic, multi-step user journeys.

Drop a comment below 👇

  • Have you used JMeter before, or is this your first time?
  • Has a "functionally correct" feature ever fallen over under load on you?
  • What APIs do you wish you knew how to load test?

All levels welcome. Let's build this together. 🙌


Faizal Shaikh | Senior Automation Engineer | Performance & AI Testing
Connect with me on LinkedIn

Top comments (1)

Collapse
 
xulingfeng profile image
xulingfeng

We use the same stack at work — JMeter + Jenkins + Python for parsing .jmx files to run scheduled API automation and load tests. It's incredibly handy once you get the pipeline wired up.