Build a load test

A load test is only as good as its data: one hard-coded user posted a thousand times hits caches and unique constraints, not your real code paths. A test bundle generates the data and the test script together.

1. Describe the data and the requests

signup-load.yaml
version: "1"
output:
  language: eng
  format: json          # k6 reads JSON data
  package: k6
  quantity: 500         # one record per iteration
scenario:
  baseURL: "${BASE_URL}"
  load:
    virtualUsers: 20
    durationSeconds: 60
  requests:
    - name: sign-up
      method: POST
      path: /api/users
      headers: { Content-Type: application/json }
      body:
        name: "{{name}}"
        email: "{{email}}"
        password: "{{password}}"
      expect: { status: [201] }
    - name: read-profile
      method: GET
      path: /api/users/by-email/{{email}}
      expect: { status: [200] }
fields:
  - { name: name, type: text, category: fullName }
  - { name: email, type: email, unique: true }
  - { name: password, type: password, length: 16 }
  • fields describe one user. unique: true keeps the sign-ups from colliding.
  • scenario.requests run in order for each record: sign up, then read the profile back.
  • {{email}} in the path or body is replaced with the record's value.
  • baseURL is a placeholder, so the same bundle runs against any environment.

2. Generate the bundle

Generate the recipe as usual — in the app or with POST /api/v1/generate. The download is a ZIP:

ghostbakery-output.zip
test.js      # the k6 script
data.json    # 500 generated users
README.md    # how to run it

3. Run it

terminal
unzip ghostbakery-output.zip -d signup-load && cd signup-load
BASE_URL=https://staging.example.com k6 run test.js

Each iteration takes the next record from data.json, runs both requests and checks their status codes. k6 prints the check results and latencies at the end.

Other tools

Change output.package — and output.format where the tool needs it — and generate again. The scenario stays the same.

package Tool Requires Scenario file Data file Status assertions
k6 JavaScript load-test script for Grafana k6. format: json test.js data.json yes
artillery YAML load-test script with a CSV payload. format: csv test.yaml data.csv
jmeter JMX test plan with a CSV data set. format: csv test-plan.jmx data.csv
postman Postman Collection for the collection runner. format: json collection.json data.json yes
hurl Hurl file for CI and end-to-end checks. format: json requests.hurl data.json yes
http .http request file for IDE HTTP clients. format: json requests.http data.json

k6, Postman and Hurl check expect.status; Artillery, JMeter and .http files carry the requests without assertions. Load settings are translated where the tool has an equivalent. See the test bundle reference for every key.

Tips

  • Size the data to the run. With fewer records than iterations, records are reused; with unique keys that means conflicts on the second pass. Generate at least as many records as the test runs iterations.
  • Point at a test environment. A load test against production is an incident. Use a staging BASE_URL.
  • Keep secrets out of the recipe. Put tokens in environment variables your tool reads, not in headers.