What API load testing actually measures

Capacity: how many requests per second before latency degrades. Answered by generating concurrent traffic and watching response times and error rates.

Correctness: does the response contain the right thing. Answered by asserting on bodies against an expectation.

A load test that checks only status codes will report a clean run while every response contains an empty list. The service was fast and wrong, and fast and wrong is worse than slow and right because nobody investigates it.

What a functional suite tells you about load, and what it does not

Generated API test plans include boundary and stress-shaped cases: oversized payloads, out-of-range values, unusual parameter combinations. Those catch a real class of failure and they are not load testing. They exercise edges one at a time rather than measuring behavior under sustained concurrency.

So the honest division is this. Use a dedicated load tool for capacity. Use functional verification for correctness, including the edge cases that only appear with awkward input. Neither substitutes for the other, and running both is cheaper than discovering the gap in production.

Three things worth checking before you load test at all

Is it correct at one request per second

  • Load testing a broken endpoint measures how fast you can be wrong.

Does it clean up

  • A load run that creates records and leaves them will change the behavior of the next run.

Is the environment representative

  • Load results from an environment with a tenth of the data are not a prediction, they are a number.

Correctness under realistic conditions

The gap worth closing is not between load and functional testing. It is that most functional suites run against a clean, idle environment, so they never see the failures that appear when data is large or state is messy. Running functional checks against an environment that has been used is a cheap way to find those.

Terminal

npm install -g @testsprite/testsprite-cli
testsprite setup

The same setup is available in the TestSprite dashboard if you would rather not install anything locally. The rest of the CLI surface is in the CLI repository.

The four things that decide whether an API suite lasts, sessions, captured values, ordering and cleanup, are covered in the API testing documentation.

Reading a load result honestly

Load results get over-interpreted more than almost any other test output, usually in two directions.

A number from an environment that does not match production is a comparison point for your next run and nothing more. Half the database, a tenth of the data, no other traffic, a different instance size. Presenting that figure as capacity is how teams end up surprised on launch day by a number they thought they had measured.

The other direction is treating a pass as evidence of health. If the run asserted only on status codes, you have measured that the service returns quickly under load, which it will do very efficiently when a query is returning an empty set. Turn on body assertions for a sample of requests and the same run tells you something.

Run correctness on every change

Load testing belongs on a schedule or before a release. Correctness belongs on every pull request, because that is when a regression is cheapest to fix.

  • The GitHub App is a webhook you set up in the TestSprite dashboard. It listens for the deployment event your pipeline already produces, so nothing in your repository changes.

  • GitHub Actions puts the step inside your own workflow, configured from the terminal.

Where TestSprite fits around a load run

TestSprite covers the correctness layer that makes a capacity number mean something. It exercises the API against the behavior you expect, including boundary and authorization cases, and reports what actually came back rather than only how fast.

Coverage is generated from a discovery pass over the running service plus whatever specification you have, so the awkward inputs are included without anyone writing them. Auto-Authentication keeps sessions alive across a run, Dynamic Variables carry values between calls, Dependency Chains derive execution order from what each case needs and produces, and Auto-Cleanup removes exactly what the run created.

The benefit is a floor under your performance work: before you spend a day measuring throughput, you know the endpoint returns the right thing. Sustained concurrency stays with your load generator, and the two run on different cadences without interfering.

Does TestSprite do load testing?

No. It verifies correctness, including boundary cases. Capacity under sustained concurrency needs a dedicated load tool.

Can we assert on response bodies in a load test?

Most load tools support it and few teams enable it, because it costs throughput on the generator. Worth doing on a sample of requests rather than all of them.

Which comes first?

Correctness. Load testing an endpoint that returns the wrong thing produces a confident number about nothing.

How often should we load test?

Before releases and after architectural changes. Continuous load testing is expensive and rarely tells you something new between those points.

What about load testing in CI?

A smoke-sized load check can work. Full capacity testing in CI usually means either a meaningless load level or a very slow pipeline.

The short version

Fast and wrong is still wrong.

API load testing answers capacity. It does not answer whether responses were correct, and a status-code-only load test will pass while the API returns nothing useful. Use a dedicated tool for capacity, verify correctness separately, and do correctness first.