Performance testing investigates how quickly a system performs useful work, how consistently it does so under load, and where its limits lie. It answers product questions: can a catalog handle an advertising campaign, will checkout remain responsive, and what happens when a queue grows?
Launching a thousand virtual users proves little by itself. A meaningful result requires a load profile, quality criteria, environment state, and the work actually completed. A CPU chart without this context can easily mislead.
The question a test should answer
Start with a testable hypothesis. For example, a new search version handles expected peak load without worsening p95 or successful-result rate. Alternatively, the system recovers normal speed after a brief surge without a manual restart.
Agree on criteria and a measurement window with the team. An illustrative criterion: at 100 search requests per second for 20 minutes, p95 full request time stays below 500 ms, technical errors below 1%, and content correctness is verified. These figures demonstrate wording; actual product requirements may differ.
Building a load model
Define scenarios, their proportions, intensity, duration, and data distribution. A catalog with 80% browsing and 20% search behaves differently from identical requests to one popular item. Include authentication, think time, cache behavior, response size, and repeated access.
Use analytics or explicit assumptions. State whether the test creates new connections, reuses sessions, and retries. A business journey may contain several HTTP requests: 100 purchase starts per second are different from 100 RPS.
Open and closed models
In a closed model, a fixed virtual-user population starts each iteration after its previous one completes. Request intensity can fall when the service slows. This suits some bounded-user populations but can hide problems under an independent incoming flow. The reduced traffic during slowdown relates to coordinated omission: some expected work never enters the measurements.
In an open model, new iterations start on a schedule independently of earlier completion. Choose the model according to the question. If arrival intensity must remain fixed, verify that the generator achieves it; missed starts and insufficient resources limit conclusions about server resilience.
Environment and test data
Record the build, infrastructure, limits, autoscaling, database configuration, and dependency state. Identify real and substituted services. An instantaneous payment mock changes journey timing and resource occupancy.
Prepare enough accounts and objects to avoid artificial uniqueness constraints or locking on one user. Include realistic large accounts and popularity skew too. A tiny dataset fits entirely in cache and produces results that may not hold with real data.
Why a small run comes first
Validate the scenario at minimal load: tokens are valid, the correct object is found, response content matches expectations, and created entities have correct relationships. HTTP 200 with an empty result caused by a bad filter does not validate a successful search.
Reconcile operation counts against server metrics and prepared data. If checkout stops at authentication, scaling creates more failed logins. A small smoke run quickly exposes script problems and validates telemetry before an expensive experiment.
Practical example: a new search version
Prepare 10,000 search phrases with realistic repetition frequencies and known assertions for selected queries. Measure the baseline and new version in the same configuration. Separate warm-up from steady-state measurement rather than hiding initial cache population in an average.
- →Increase intensity to 100 requests per second according to the agreed profile.
- →Maintain a 20-minute stable window and record actual start, completion, and error rates.
- →Compare p50, p95, p99, response correctness, queue size, CPU, memory, and database waits.
- →After reducing load, verify that delays and queues return to baseline.
A new version with p95 of 420 ms still fails if 3% of requests return incorrectly empty results. If the generator achieves only 60 of the required 100 requests per second, the load criterion cannot be claimed as met.
Finding a bottleneck
Correlate client symptoms with server signals using shared times and identifiers. Higher latency alongside database connection waits suggests a pool-related hypothesis but does not prove it. Low overall CPU does not rule out queues, locks, or external-service limits.
Change one significant variable per experiment. After enlarging a pool, check whether the queue moved into the database or other journeys worsened. Seek the degradation mechanism rather than the most prominent chart.
What a report should contain
Describe the goal, profile, environment, data, criteria, actual load, and limitations. Show timing distributions alongside errors and useful throughput. For a threshold, identify the first violated criterion and whether the system recovered.
Common mistakes include averages instead of tail latency, aggregate percentages across different operations, hidden retries, and incomparable runs. One successful test does not guarantee performance under every load. After a fix, repeat the relevant experiment under the same conditions; select additional runs according to changed risk.
Key takeaways for QA
Evaluate performance through useful work under known conditions. Scenarios must be correct, generators must achieve the stated load, and criteria must exist before execution. A good conclusion explains what the system handled, where degradation began, and the supporting evidence.