Performance Testing: Load, Stress, Soak, and Spike Testing Guide
Performance testing evaluates how a system behaves under various load conditions — measuring response times, throughput, resource utilization, and stability to ensure it meets performance requirements before reaching production.
What You’ll Learn
- The four types of performance testing: load, stress, soak, and spike
- How to write performance tests with k6 and JMeter
- Key performance metrics and how to interpret them
- How to set performance baselines and thresholds
- Common performance testing pitfalls and best practices
Why Performance Testing Matters
Performance failures damage user trust and revenue. Amazon found that every 100ms of latency cost 1% in sales. Google found that a 500ms delay reduced traffic by 20% . Performance testing prevents slow load times, outages during traffic spikes, and memory leaks that crash servers after weeks of running. Without performance testing, you discover these problems when users do.
Doda Browser uses performance testing to ensure page load times stay under 500ms even with dozens of open tabs — every millisecond of delay affects user experience directly.
Learning Path
flowchart LR
A[Unit Testing] --> B[Integration Testing]
B --> C[Performance Testing<br/>You are here]
C --> D[QA & Observability]
D --> E[Production Monitoring]
style C fill:#f90,color:#fff
Types of Performance Testing
Load Testing
Simulates expected user traffic to verify the system performs within acceptable metrics under normal conditions.
Goal: Confirm response times, throughput, and error rates meet requirements.
Stress Testing
Increases load beyond expected maximum to find the system’s breaking point and observe how it fails.
Goal: Identify the maximum capacity and ensure graceful degradation.
Soak Testing (Endurance)
Runs moderate load for an extended period (hours or days) to catch memory leaks, connection pool exhaustion, and resource accumulation.
Goal: Verify long-term stability.
Spike Testing
Suddenly increases load by 200-500% to test how the system handles traffic surges.
Goal: Verify auto-scaling, queue handling, and recovery.
Performance Testing with k6
k6 is a modern, scriptable load testing tool. Install it with brew install k6 or download from k6.io.
// load_test.js
import http from 'k6/http';
import { check, sleep } from 'k6';
import { Rate, Trend } from 'k6/metrics';
const errorRate = new Rate('errors');
const responseTime = new Trend('response_time');
export const options = {
stages: [
{ duration: '2m', target: 50 }, // Ramp up to 50 users
{ duration: '5m', target: 50 }, // Stay at 50 users
{ duration: '2m', target: 0 }, // Ramp down
],
thresholds: {
http_req_duration: ['p(95)<500'], // 95% of requests under 500ms
errors: ['rate<0.05'], // Error rate below 5%
},
};
export default function () {
const BASE_URL = 'https://api.example.com';
// Test GET endpoint
const getRes = http.get(`${BASE_URL}/api/users`);
check(getRes, {
'get users status is 200': (r) => r.status === 200,
'get users response time < 300ms': (r) => r.timings.duration < 300,
});
errorRate.add(getRes.status !== 200);
responseTime.add(getRes.timings.duration);
sleep(1);
}Run it:
k6 run load_test.jsExpected output:
✓ get users status is 200
✓ get users response time < 300ms
checks.........................: 100.00% ✓ 3000 ✗ 0
data_received..................: 12 MB 670 kB/s
http_req_blocked...............: avg=1.2ms p(95)=4.5ms
http_req_duration..............: avg=124.5ms p(95)=287.3ms
http_req_waiting...............: avg=121.3ms p(95)=280.1ms
✓ http_req_duration..............: p(95)=287.3ms < 500ms
✓ errors.......................: 0.00% ✓ 0 ✗ 3000Stress Testing with k6
// stress_test.js
export const options = {
stages: [
{ duration: '3m', target: 100 },
{ duration: '5m', target: 200 },
{ duration: '3m', target: 500 },
{ duration: '2m', target: 1000 },
{ duration: '3m', target: 0 },
],
thresholds: {
http_req_duration: ['p(90)<2000'],
http_req_failed: ['rate<0.10'],
},
};
export default function () {
const res = http.get('https://api.example.com/api/search?q=test');
check(res, {
'search status is 200 or 429': (r) => r.status === 200 || r.status === 429,
});
sleep(0.5);
}Stress tests help you find the breaking point — the load level where response times spike, errors increase, or the server becomes unresponsive.
Soak Testing with k6
// soak_test.js
export const options = {
stages: [
{ duration: '5m', target: 100 },
{ duration: '8h', target: 100 }, // Run for 8 hours
{ duration: '5m', target: 0 },
],
thresholds: {
http_req_duration: ['p(95)<1000'],
http_req_failed: ['rate<0.01'],
},
};Monitor memory and CPU during soak tests. A steady increase in memory usage indicates a leak.
Performance Testing with JMeter
JMeter is a GUI-based performance testing tool popular for enterprise environments.
<!-- Test plan snippet (JMeter saves as .jmx, which is XML) -->
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="User Simulation">
<stringProp name="ThreadGroup.num_threads">100</stringProp>
<stringProp name="ThreadGroup.ramp_time">30</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController">
<stringProp name="LoopController.loops">10</stringProp>
</elementProp>
</ThreadGroup>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy">
<stringProp name="HTTPSampler.path">/api/users</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<stringProp name="HTTPSampler.domain">api.example.com</stringProp>
</HTTPSamplerProxy>Run JMeter from the command line:
jmeter -n -t test-plan.jmx -l results.jtl -e -o reports/The -e -o flags generate an HTML report with charts.
Performance Metrics
| Metric | What It Measures | Good Target |
|---|---|---|
| Response time (p50) | Median request duration | < 200ms |
| Response time (p95) | 95th percentile | < 500ms |
| Response time (p99) | 99th percentile (worst case) | < 1000ms |
| Throughput | Requests per second | Varies by system |
| Error rate | Percentage of failed requests | < 1% |
| CPU usage | Server CPU utilization | < 70% |
| Memory usage | RAM consumption | Stable over time |
Interpreting Results
- Gradual increase in response time as load grows: Expected for most systems up to a point
- Sudden spike in response time: System has reached capacity — CPU saturates, connection pool exhausts, or database locks
- Increasing error rate: Server is rejecting requests — check for rate limiting, circuit breakers, or resource exhaustion
- Growing memory over time: Memory leak — objects not being garbage collected
Common Performance Testing Mistakes
1. Testing Only the Happy Path
Performance tests that hit cached data with simple queries don’t represent real usage.
Fix: Include realistic data shapes, query complexity, and traffic patterns.
2. Testing Against a Weak Environment
Testing on a laptop or underpowered server gives misleading results.
Fix: Test in an environment comparable to production (same CPU, memory, network, database).
3. Insufficient Warm-Up
JIT compilation, connection pooling, and caching need time to stabilize.
Fix: Include a warm-up phase before recording measurements.
4. Ignoring External Dependencies
Your app may be fast, but if the database or third-party API is slow, users still have a poor experience.
Fix: Monitor and test dependencies as part of your performance test.
5. Not Setting Baselines
Without a performance baseline, you can’t tell if a deployment made things better or worse.
Fix: Run performance tests regularly and track results over time.
6. Stopping When Things Fail
A performance test that fails on the first error misses the full picture of degradation.
Fix: Let the test continue and observe how the system behaves under sustained failure conditions.
7. Neglecting Client-Side Performance
Server response time is only part of the user experience. Network latency, rendering, and JavaScript execution matter too.
Fix: Use browser-based performance testing (Lighthouse, Playwright) alongside server-side tests.
Practice Questions
1. What are the four types of performance testing?
Load (normal traffic), stress (find breaking point), soak (long-term stability), spike (sudden traffic surge).
2. What does p95 response time tell you?
95% of requests are faster than this value. It shows the experience of most users, excluding the slowest 5%.
3. Why is soak testing important?
It catches memory leaks, connection pool exhaustion, and resource accumulation that only appear after hours or days of operation.
4. What should you check if response times spike suddenly under load?
CPU saturation, connection pool limits, database locks, or rate limiting being triggered.
5. What is the purpose of a warm-up phase in performance testing?
To allow JIT compilation, connection pools, and caches to stabilize before recording measurements.
Challenge: Write a k6 script that performs a spike test on a public API. Start with 10 users, then spike to 500 users in 30 seconds. Verify the error rate stays below 5% and p95 response time stays under 2 seconds.
FAQ
What’s Next
| Tutorial | What You’ll Learn |
|---|---|
| Security Testing Guide | Finding vulnerabilities in your applications |
| Continuous Testing in CI/CD | Integrating performance tests into pipelines |
| Quality Metrics and Measurement | Measuring and tracking software quality |
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Updated 2026-06-20.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro