Performance Testing
Beginner 11 min read Performance Testing

Types of Performance Testing

Performance testing is an umbrella term covering smoke, load, spike, soak, stress and volume tests — each answers a different capacity or stability question. Learn which type to pick for the question you are trying to answer.

load teststress testspike testsoak testsmoke testvolume test
Introduction

What is this?

Performance testing measures how a system behaves under load: response times, throughput and resource usage. It is not one activity but a suite — smoke, load, spike, soak, stress and volume tests each answer a different question about capacity and stability. The goal is to validate that a service meets its response-time and error-rate targets at expected traffic, and to discover the load at which it degrades.

Motivation

Why do you need it?

  • Catches regressions that functional tests miss — a slow endpoint or exhausted connection pool only appears under concurrent load.
  • Establishes capacity: you learn how many users or requests the system can sustain before latency blows up.
  • Validates SLOs and budgets against realistic traffic patterns before they become customer-facing incidents.
  • Reveals resource exhaustion: thread pools, database connections, CPU, memory and file descriptors all fail differently under pressure.
  • Provides a repeatable, automated gate in CI so performance is tracked like any other quality attribute.
  • Spike and soak tests expose failure modes a steady load test cannot, such as GC pauses, memory leaks or slow connection reuse.
Think about it

Mental model

Imagine

A fitness test

Think of

A performance test

You first measure resting heart rate (baseline), then ramp the treadmill until you get out of breath, and finally push to your max to find the breaking point. Performance testing does the same for software: measure normal, ramp up, and find the ceiling.

Mechanics

How it works

  • Define measurable targets first: response-time percentiles (p95/p99), error rate and throughput at an expected concurrent-user count.
  • Pick the test type that answers the question — smoke, load, spike, soak or stress — and configure a realistic workload model.
  • Generate the load with a tool such as k6, JMeter or Gatling while the system is instrumented with metrics, logs and traces.
  • Collect results: latency percentiles, throughput and error rate, plus server-side CPU, memory, GC and database metrics.
  • Analyze results against the baseline and targets, identify bottlenecks, fix, and re-run until the targets are met.

Choosing the right type of performance test based on the question you are asking.

Question
Smoke test
Load test
Spike test
Soak test
Report
Reference

Key commands

k6 run --scenario smoke script.js

Run only the smoke scenario to verify the script and the target pipeline.

scenario: smoke  ✓✓ 1 iterations · 0 failed
k6 run --scenario load script.js

Run only the sustained load scenario from the multi-scenario script.

k6 run --scenario spike script.js

Run only the spike scenario to exercise sudden, large load jumps.

ab -n 1000 -c 50 http://localhost:8080/api/health

Quick concurrency probe with ApacheBench as a sanity check before full-scale tests.

Time per request: 12.34 [ms] (mean)
hey -z 30s -c 100 http://localhost:8080/api/health

Generate 30 seconds of sustained load with 100 concurrent workers using hey.

jmeter -n -t load-test.jmx -l results.jtl

Run a JMeter plan headlessly and record every sample to a results file.

Hands-on

Examples

Smoke, load and spike profiles in one k6 script

Smoke, load and spike profiles in one k6 script
import http from "k6/http"
import { check } from "k6"
import { sleep } from "k6"
export const options = {
scenarios: {
smoke: {
executor: "shared-iterations",
vus: 1,
iterations: 1,
startTime: "0s",
},
load: {
executor: "ramping-vus",
startVUs: 0,
stages: [
{ duration: "30s", target: 50 },
{ duration: "2m", target: 50 },
{ duration: "30s", target: 0 },
],
startTime: "1m",
},
spike: {
executor: "ramping-vus",
startVUs: 0,
stages: [
{ duration: "5s", target: 500 },
{ duration: "10s", target: 500 },
{ duration: "30s", target: 0 },
],
startTime: "4m30s",
},
},
}
export default function () {
const res = http.get("http://localhost:8080/api/health")
check(res, {
"status is 200": (r) => r.status === 200,
"p95 under 200ms": (r) => r.timings.duration < 200,
})
sleep(1)
}

Three scenarios run from the same script: a one-iteration smoke check, a sustained load phase at 50 VUs, and a spike to 500 VUs. Each answers a different question — does the pipeline work, can it sustain expected traffic, and does it survive a sudden surge? The startTime fields sequence them so all three run in a single k6 run.

Real world

In production

  • A weekly scheduled load test in staging reuses the same scenarios used in production capacity reviews.
  • Smoke tests run in every CI merge to catch gross performance regressions within minutes.
  • Soak tests run overnight against every release candidate to catch memory leaks that only appear after hours.
  • Spike tests are paired with autoscaling drills to confirm the fleet can absorb a traffic surge before a launch event.
Guidelines

Best practices

  • Start with a smoke test, then load, then spike or soak — never jump straight to a full-scale stress test.
  • Pin every test to a specific question and target; a test without an SLO is just a benchmark.
  • Run against realistic data volume and a realistic mix of endpoints, not a single happy-path URL.
  • Use a dedicated test environment that matches production in configuration — pool sizes, limits and replica counts.
  • Freeze both the application version and the infrastructure during the test window so results are comparable.
Watch out

Common mistakes

  • Treating 'performance test' as a single event instead of a suite of test types with different questions.
  • Testing against the staging database's tiny dataset — indexes that are fast in QA never show up as slow in prod.
  • Reading results before caches, JIT compilers and connection pools have stabilized during the warm-up window.
  • Running the test from a laptop or a single box that becomes the bottleneck itself.
Root cause analysis

Common issues

Error
Timeout while waiting for a response
Root cause

Server-side resource exhaustion (thread pool, connections) under load.

Fix

Take a thread dump and connection-pool metrics during the test, then size pools up or optimize the bottleneck.

Error
Load generator CPU at 100% and error rate climbing
Root cause

The client cannot keep up with the requested concurrency.

Fix

Move to distributed load generators or lower concurrency so the server is the bottleneck.

Error
Results vary wildly between identical runs
Root cause

Shared infrastructure or noisy neighbors interfering with the test.

Fix

Use a dedicated environment or repeat the test several times and report the median across runs.

When things break

Debugging tips

  • Check the load generator's own CPU and network first — a saturated client invalidates every result.
  • Correlate the client-side latency curve with server-side CPU and GC: flat latency with climbing CPU means the server is absorbing the load.
  • Record thread and connection-pool metrics; exhausted pools cause timeouts that look like network faults.
  • Re-run the same test twice — if results are wildly different, the environment is noisy, not the app.
Interviews

Interview checkpoint

Practice

Hands-on lab

Classify and Run Your First Load Test
30 min · beginner
In progress
Objectives
  • Map testing goals to the correct performance test type
  • Write a k6 script with smoke and load scenarios
  • Run each scenario and inspect the summary report
  • Interpret latency percentiles and error rate against targets

Classify and Run Your First Load Test

30 min · beginner

0/5 steps
0%
sandbox · Linux sandbox
$
Try these commands
Test yourself

Quick quiz

0/3
1

Which test type pushes the system beyond its expected capacity to find the breaking point?

2

A smoke test is designed to validate the full test pipeline with minimal load before running large-scale tests.

3

You need to find memory leaks that only surface after several hours of steady usage. Which test type is appropriate?

Quick reference

Cheat sheet

Test types at a glance
SmokeVerify pipeline with minimal load
LoadExpected traffic, fixed window
StressPush past capacity to breaking point
SpikeSudden burst, then observe recovery
SoakSteady load for hours, find leaks
VolumeLarge data volumes, find data-path limits
Go deeper

Official documentation