How to do performance testing: 8 steps from the question to the report
Performance testing measures how fast and how error-free a system works under the expected load, and under more than expected. Running the test is the small part: unless you write down beforehand what you are asking, where you measure and which result counts as a pass, the charts say nothing. This guide walks through the work in order; each step links to the guide that goes deeper.
1. Write down the question and the target
"Is the system fast?" is not a measurable question. A good question names a flow, a load and a limit: does the order flow stay under a p95 of 800 ms and under 1% errors at 300 requests per second? The load should come from data, not a guess: the requests/s of the busiest hour in production, the multiplier expected for a campaign. Use percentiles rather than the average; the average hides most of the slow requests (what p95 and p99 mean).
Question: Does the order flow hold on campaign day?
Target: 300 requests/s, p95 < 800 ms, error rate < 1%
Where: staging (same version and data volume as production)
Flow: sign in → search → add to cart → place order
Duration: 1 min warm-up + 15 min at the target2. Pick the environment
A result is only as right as the environment you measured. The test environment should run the same version as production, hold a similar volume of data (a ten-row table makes every query look fast) and have the same cache, queue and third-party settings. If you measure a smaller environment, do not scale the result up to production; know that you found that environment's own limit. If you test in production, pick a quiet hour, tell the teams involved and use only requests that change no data.
3. Build the scenario
The scenario should do what real users do: a test that only calls the home page never sees the slow query in the order flow. There are three short ways to build the flow: import an OpenAPI file or a Postman collection if your API has one (load tests from Swagger/OpenAPI and Postman), do the flow once in the browser and save it as HAR (load tests from a HAR file), or add the steps in the editor without code (load testing without scripting).
- Test data: if every VU searches the same product as the same user, the cache answers everything. Spread users and search terms from a CSV file.
- Correlation: the token a sign-in returns or the id of a new order should pass to later requests as a variable; a constant replayed means the server measures a single session.
- Checks: add a check to every step that says the response is right: status 200, the expected field in the body. A fast error page is not a good response time.
4. Pick the load model
You can give the load in two ways. By VU count (closed model): N virtual users repeat the flow; when the system slows down, the request rate drops too. By request rate (open model): N iterations start every second; the incoming traffic does not drop when the system slows down, just like real users. If your target is "300 requests per second", measure by request rate; otherwise the test eases off as the system slows down and the result looks better than it is (coordinated omission).
In Spitfire the load model is in the editor's Load model section: Constant VUs, Ramping VUs, Constant arrival rate, Ramping arrival rate and the iteration models (Shared iterations, Per-VU iterations). In the ramping models each stage's duration and target show on a plan chart; pacing starts a VU's iterations at a fixed interval.
5. Write the pass/fail criteria into the test
The target from step 1 should not be left to whoever reads the report; it should be written into the test as thresholds. In Spitfire the editor's Thresholds and guard tab picks the metric, the expression and the scope; when the run ends each threshold is marked passed or failed, and in CI the run's result follows from them:
"thresholds": [
{ "metric": "req_duration", "expr": "p(95)<800" },
{ "metric": "req_failed", "expr": "rate<0.01" }
]A test's first minute is often not representative: connection pools fill, caches warm up, the JIT compiles. Options → Warm-up leaves that time out of the "after warm-up" section, and thresholds are judged on the after-warm-up values. The report also has an Apdex score to see the target in a single number.
6. Run from small to large
- Smoke test: a few iterations with 1–2 VUs. Does the flow work, do the checks pass, is the test data right? If something is wrong here, a load test only multiplies the error.
- Load test: at the expected load, 10–30 minutes including the warm-up. This run answers your question.
- Stress or breakpoint: raise the load step by step and find where the system breaks; this shows how much headroom you have (breakpoint testing).
- Spike and soak: a sudden jump in traffic and a steady load for hours; memory leaks and filling disks only show in a long run (load, stress, spike and soak testing).
The machine that generates the load must not be the bottleneck itself: if the runner's CPU is full, you are measuring the runner, not the target. Split the load across several runners and, if needed, locations. If the target struggles unexpectedly, the editor's guard slows down or stops the load based on the target's own p95 and error rate.
7. Read the results and find the bottleneck
- Errors first: with a high error rate, response times lose their meaning. Group the errors by status code and message; 5xx points at the server, timeouts at a queue or a connection pool.
- Read the request rate and p95 together: if requests/s goes flat while the load rises and p95 climbs, the system is saturated; the load at that point is your capacity. In Spitfire, while the mouse moves over one of a run's charts, every chart shows the same second.
- Look step by step: the flow's average hides a single slow step. The steps table shows each request's p95 separately; with a ramping load the stage table gives each step's result.
- Add the server side: a response time does not say what is slow. With CPU, memory, database connections and traces on the same time axis, the bottleneck is often found at a glance (OpenTelemetry: closer to the root cause).
After changing something (an index, a pool size, a cache), run the same test again at the same load and compare the two runs. Change several things at once and you cannot tell which one worked.
8. Make it repeatable
A one-off performance test holds until the next release. Take a good run as the reference with Set as baseline; later runs are compared with it and a regression shows as a finding. Put the test into your CI/CD pipeline so that every release is measured by the same criteria (performance testing in CI/CD), and watch the critical endpoints in production between releases with synthetic monitoring (synthetic monitoring).
Frequently asked questions
Are performance testing and load testing the same thing?Tests
How long should a performance test run?Tests
How many virtual users (VUs) should I use?Tests
Can performance tests run in production?Tests
Which tool should I use for performance testing?Tests
Spitfire installs on Docker or Kubernetes with one command; every testing feature and protocol is open in the free edition.