Skip to main content
hitspec includes a built-in stress testing engine. You do not need a separate tool — the same .http files you use for functional tests can drive load tests. This tutorial covers rate-based testing, virtual user mode, multi-phase profiles, and threshold-based pass/fail.

Prerequisites

Quick Start

The simplest way to stress test is with CLI flags:
hitspec run api.http --stress --duration 30s --rate 10
This sends 10 requests per second for 30 seconds against the requests defined in api.http.
1

Create a test file for stress testing

Create stress.http with a simple request:
stress.http
@baseUrl = https://httpbin.org

### Health check
# @name healthCheck
# @tags smoke

GET {{baseUrl}}/get

>>>
expect status 200
expect duration < 2000
<<<

### Create item
# @name createItem
# @tags write

POST {{baseUrl}}/post
Content-Type: application/json

{
  "name": "Load test item",
  "timestamp": "{{$timestamp()}}"
}

>>>
expect status 200
<<<
Use {{$timestamp()}} or {{$uuid()}} to generate unique values on every request. This avoids caching effects and simulates realistic traffic.
2

Run a rate-based stress test

Rate mode sends a fixed number of requests per second:
hitspec run stress.http --stress --duration 1m --rate 20
This runs for 1 minute at 20 requests per second. hitspec distributes the load across all requests in the file.Output:
Stress test: rate=20 rps, duration=1m0s

  Requests:  1200 total, 1195 passed, 5 failed
  Duration:  1m0.2s
  RPS:       19.92 avg

  Latency:
    p50:   45ms
    p95:   123ms
    p99:   287ms
    max:   412ms

  Error Rate: 0.42%
3

Run a virtual user stress test

VU mode simulates concurrent users, each sending requests sequentially:
hitspec run stress.http --stress --duration 1m --vus 10 --think-time 500ms
This creates 10 virtual users, each waiting 500ms between requests. Unlike rate mode, VU mode models real user behavior where each user completes a request before starting the next.
4

Add ramp-up

Ramp up gradually to avoid overwhelming the server at startup:
hitspec run stress.http --stress --duration 2m --rate 50 --ramp-up 30s
The rate increases linearly from 0 to 50 rps over the first 30 seconds, then holds at 50 for the remaining 90 seconds.
5

Set pass/fail thresholds

Thresholds let you define success criteria. The test exits with code 1 if any threshold is violated:
hitspec run stress.http --stress --duration 1m --rate 20 \
  --threshold "p95<200ms,errors<1%,rps>15"
Available threshold metrics:
MetricOperatorExampleDescription
p50<, <=p50<100ms50th percentile latency
p95<, <=p95<200ms95th percentile latency
p99<, <=p99<500ms99th percentile latency
max<, <=max<1sMaximum latency
errors<, <=errors<1%Error rate percentage
rps>, >=rps>50Minimum requests per second
Combine multiple thresholds with commas.

Configuration File

For repeatable stress test configurations, define profiles in hitspec.yaml.

Rate-based Profile

hitspec.yaml
stress:
  profiles:
    smoke:
      duration: 30s
      rate: 5
      thresholds:
        p95: "500ms"
        errors: "0%"

    load:
      duration: 5m
      rate: 50
      rampUp: 1m
      maxVUs: 200
      thresholds:
        p95: "200ms"
        p99: "500ms"
        errors: "1%"
        rps: "45"

    spike:
      duration: 2m
      rate: 200
      rampUp: 10s
      maxVUs: 500
      thresholds:
        p99: "1s"
        errors: "5%"
Run a specific profile:
hitspec run stress.http --stress --profile load

Virtual User Profile

hitspec.yaml
stress:
  profiles:
    realistic:
      duration: 10m
      vus: 50
      thinkTime: 1s
      rampUp: 2m
      maxVUs: 100
      thresholds:
        p95: "300ms"
        errors: "0.5%"
VU mode is better for simulating real user behavior, where each user thinks between requests. Rate mode is better for measuring raw throughput.

Profile Strategies

Smoke Test

Verify the system handles minimal load without errors. Run this on every deploy.
smoke:
  duration: 30s
  rate: 5
  thresholds:
    errors: "0%"
    p95: "500ms"

Load Test

Sustained normal traffic levels. Verify performance under expected conditions.
load:
  duration: 10m
  rate: 100
  rampUp: 2m
  thresholds:
    p95: "200ms"
    p99: "500ms"
    errors: "0.5%"

Stress Test

Push beyond normal limits to find the breaking point.
stress:
  duration: 5m
  rate: 500
  rampUp: 1m
  maxVUs: 1000
  thresholds:
    errors: "5%"

Spike Test

Sudden traffic surge to test auto-scaling and recovery.
spike:
  duration: 3m
  rate: 1000
  rampUp: 5s
  thresholds:
    p99: "2s"
    errors: "10%"

Per-Request Configuration

You can control how individual requests participate in stress tests using metadata:
### Setup: create test data
# @name setup
# @stress.setup true

POST {{baseUrl}}/test-data
Content-Type: application/json

{"name": "stress test fixture"}

>>>
expect status 201
<<<

### Main endpoint under test
# @name getItems
# @stress.weight 3

GET {{baseUrl}}/items

>>>
expect status 200
expect duration < 500
<<<

### Secondary endpoint
# @name getItem
# @stress.weight 1

GET {{baseUrl}}/items/1

>>>
expect status 200
<<<

### Teardown: clean up
# @name teardown
# @stress.teardown true

DELETE {{baseUrl}}/test-data

>>>
expect status 200
<<<
DirectiveDescription
@stress.weight NRelative frequency (default 1). A weight of 3 means 3x more requests.
@stress.think NThink time in ms after this request (VU mode).
@stress.skipExclude this request from stress testing.
@stress.setupRun once before the stress test starts.
@stress.teardownRun once after the stress test ends.

Stress Testing in CI

Combine stress profiles with the GitHub Action for automated performance gates:
.github/workflows/stress.yml
name: Stress Tests

on:
  push:
    branches: [main]

jobs:
  stress:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Smoke load test
        uses: abdul-hamid-achik/hitspec@v1
        with:
          files: tests/api.http
          stress: true
          duration: 1m
          rate: 10
          threshold: "p95<500ms,errors<0.5%"
See the CI/CD example for complete workflow patterns.

Reading the Output

A stress test run produces a summary like this:
Stress test: rate=50 rps, duration=2m0s, rampUp=30s

  Requests:  5847 total, 5812 passed, 35 failed
  Duration:  2m0.1s
  RPS:       48.72 avg

  Latency:
    p50:   32ms
    p95:   156ms
    p99:   342ms
    max:   891ms

  Error Rate: 0.60%

  Thresholds:
    p95 < 200ms .... PASS (156ms)
    p99 < 500ms .... PASS (342ms)
    errors < 1% .... PASS (0.60%)
    rps > 40 ....... PASS (48.72)

4/4 thresholds passed
If any threshold fails, the exit code is 1 and the failing threshold is marked:
  Thresholds:
    p95 < 200ms .... FAIL (267ms)
    errors < 1% .... PASS (0.60%)

1/2 thresholds passed

Next Steps