Skip to content
Performance Testing: Load, Stress, Soak, and Spike Testing Guide

Performance Testing: Load, Stress, Soak, and Spike Testing Guide

DodaTech Updated Jun 20, 2026 7 min read

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.js

Expected 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         ✗ 3000

Stress 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

MetricWhat It MeasuresGood Target
Response time (p50)Median request duration< 200ms
Response time (p95)95th percentile< 500ms
Response time (p99)99th percentile (worst case)< 1000ms
ThroughputRequests per secondVaries by system
Error ratePercentage of failed requests< 1%
CPU usageServer CPU utilization< 70%
Memory usageRAM consumptionStable 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

How often should I run performance tests?
Run them on every major deployment and at least weekly as part of CI for critical services.
What is the difference between load testing and stress testing?
Load testing verifies performance under expected traffic. Stress testing pushes beyond expected traffic to find the breaking point.
How many virtual users should I simulate?
Base this on your expected traffic. For a typical web app, start with 50-100 concurrent users and increase until you find the limit.
Should I performance test in production?
Carefully — running performance tests against production risks degrading real user experience. Use a staging environment that mirrors production, or use production traffic mirroring (shadowing).
What tools are best for performance testing?
k6 is excellent for API testing (JavaScript, scriptable, CI-friendly). JMeter is stronger for GUI-based test creation and enterprise reporting. Locust is good for Python teams.

What’s Next

TutorialWhat You’ll Learn
Security Testing GuideFinding vulnerabilities in your applications
Continuous Testing in CI/CDIntegrating performance tests into pipelines
Quality Metrics and MeasurementMeasuring 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