Capacity and Scalability Testing
Capacity testing measures the most load a system can handle while it still meets its performance objectives. The answer is a number with its conditions attached: "the order API on four application servers handles 1,450 requests per second with p95 under 500 ms and under 0.5% errors, for the agreed request mix". One step more and an objective fails.
Scalability testing asks how that number changes when resources are added or the work grows: do eight servers give twice the capacity of four, and do queries stay fast when the database holds ten times more rows? Together, the two tests give capacity planning measurements instead of guesses.
Why it matters
Capacity decisions are made whether anyone tests or not: how many servers to run during a sale, when to buy a larger database, whether autoscaling is enough. Without measurements they are guesses. Guess low and the system fails at peak in front of real customers; guess high and the company pays for servers that add nothing, which is exactly what happens when the database is the limit.
For the tester the question becomes "how much can it take, what runs out first, and what do we gain by adding more?". Stress testing found where the system breaks and soak testing whether it lasts; capacity and scalability testing find the usable limit below the break and whether the architecture can grow past it.
Capacity: the most load that still meets the objectives
The ISTQB Performance Testing syllabus describes capacity testing as finding how many users and/or transactions a system supports while still meeting its stated performance objectives, which can also be stated as data volumes. ISO/IEC 25010 lists capacity under performance efficiency, with parameters such as concurrent users, transaction throughput and database size. So every capacity test names its dimension.
Capacity is not the breaking point. A system usually keeps answering well past its capacity, only too slowly or with too many errors. Capacity is the last load level at which every objective holds; carrying on until something breaks is stress testing.
- Fix the objectives first, for example p95 under 500 ms and errors under 0.5%. Without them there is only a breaking point.
- Use the workload model from the earlier lessons: a browse-heavy mix and a checkout-heavy mix give different capacities.
- Raise the load in equal steps and hold each step until it is steady, for example 10 minutes, so every step is a small load test.
- Record per step: throughput, p95 and p99, error rate, and CPU, memory, connection and queue usage. The first failing step shows which objective broke and which resource ran out.
Try it: Performance Test Data Generator Try it: Concurrent Request Test Generator
Scalability: scaling up and scaling out
The ISTQB Performance Testing syllabus describes scalability testing as checking whether a system can grow, for example to more users or more stored data, to meet future requirements beyond today's without violating its current performance requirements or failing. ISO/IEC 25010:2023 lists scalability as a sub-characteristic of flexibility. In practice the growth is met by adding resources in one of two ways.
Vertical scaling (scaling up) gives one server more CPU, memory or faster storage: no code change, but there is a ceiling, resizing often needs a restart, and the server stays a single point of failure. Horizontal scaling (scaling out) adds instances, identical copies of the application, behind a load balancer: no fixed ceiling, but instances must be stateless (no user session kept in one instance's memory), and shared parts such as the database or a rate-limited third-party API do not multiply with them.
A scalability test runs the same capacity test at several sizes and changes one thing at a time: 1, 2, 4 and 8 instances, or 4, 8 and 16 vCPU (virtual processor cores), with the same data, mix and objectives. Compare sizes with scaling efficiency, efficiency = C(N) / (N × C(1)), where C(N) is the capacity with N units; 100% means every unit adds its full share.
- Scaling up: check that the software uses the new resources. A fixed thread pool, the set number of worker threads that serve requests at the same time, can leave added cores idle.
- Scaling out: check that sessions survive when a request lands on another instance and that scheduled jobs do not run once per instance.
- Scaling with data: repeat the test at the data volume forecast for next year. A query that is fast on one million rows may not be on twenty million.
Try it: Load Test Data Generator Try it: Large JSON Dataset Generator
Worked example: the order API before a seasonal sale
An online store forecasts a peak of 1,800 requests per second on its order API during the yearly sale. The objective is p95 under 500 ms and errors under 0.5% for the agreed request mix. The test environment mirrors production: 4-vCPU application instances behind a load balancer, one 8-vCPU database server and production-sized data. The team ran the stepped capacity test at 1, 2, 4, 6 and 8 instances.
- Up to 4 instances the API scales out almost linearly: the application tier is the limit.
- From 4 to 8 instances capacity rises by only 80 req/s while database CPU reaches 98% and its connection pool fills: the bottleneck has moved to the database.
- The architecture tops out at about 1,500 req/s, below the forecast, and no number of application instances closes the gap. The finding is "scale or relieve the database", not "add servers".
- Next experiment: give the database more resources or less work, for example by adding a missing index or caching product reads, then repeat the 4, 6 and 8 instance runs.
Objective: p95 < 500 ms and errors < 0.5 % (agreed request mix)
Instances Capacity (req/s) Efficiency Saturated first
1 400 100 % app CPU 92 %
2 780 98 % app CPU 90 %
4 1,450 91 % DB CPU 88 %
6 1,520 63 % DB CPU 97 %
8 1,530 48 % DB CPU 98 %, DB pool full
Efficiency = capacity / (instances x 400)
Forecast peak for the sale: 1,800 req/sReading the scaling curve
Plot capacity against the number of units and compare it with the straight line of perfect scaling. The shape says what to do next.
- Linear: every unit adds its full share. Capacity can be bought with more units while the shared parts keep up.
- Sub-linear: each unit adds a little less, because of coordination and shared resources. Scaling works, but each request costs more.
- Plateau: capacity stops rising, as in the worked example. A shared component is saturated; find it and scale it, because more units only add cost.
- Retrograde: capacity falls as units are added, often because instances compete for a lock or a connection pool. Report it as a defect.
- LinearEvery instance adds 400 req/s (efficiency near 100%): 5 instances reach the forecast.
Reference line:forecast peak: 1,800 req/s
- Sub-linearEach instance adds a little less (72% efficiency at 8): 6 instances give 1,860 req/s, at a higher cost per request.
Reference line:forecast peak: 1,800 req/s
- Plateau: the order APINear-linear to 4 instances, then flat near 1,530 req/s as the database saturates: no instance count reaches the forecast.
Reference line:forecast peak: 1,800 req/s
- RetrogradePast 4 instances capacity falls, as instances compete for a lock or a connection pool: more resources make it worse.
Reference line:forecast peak: 1,800 req/s
more instances, less capacity
The linear, sub-linear and retrograde curves are illustrative; the plateau uses the measured numbers from the worked example. All four plots share the same scales.
From test results to a capacity plan
Capacity planning decides how much infrastructure is needed, and by when, to serve forecast demand with a safety margin. The Google SRE book names what it requires: a demand forecast covering organic growth and inorganic events such as launches and campaigns, reaching beyond the time needed to add capacity, and regular load testing that relates raw capacity (servers, disks) to service capacity.
Testers supply that second half as a capacity statement: "400 req/s per 4-vCPU instance for the agreed mix, near-linear up to 4 instances; the architecture tops out at about 1,500 req/s because database CPU saturates".
- Headroom: how far below tested capacity production should stay at peak. It is a team decision; with an 80% ceiling, a 1,800 req/s forecast needs 2,250 req/s of tested capacity.
- Spare units: one instance more than the calculation (N+1), so losing one still leaves enough capacity.
- Lead time: minutes to add an autoscaled instance, possibly weeks for a larger database. The slowest resource decides how early the plan must act.
- Production thresholds: the ISTQB syllabus notes that once scalability limits are known, thresholds can be monitored in production, for example an alert when database CPU passes 75%.
Common mistakes
- Reporting the breaking point as the capacity. Capacity is the last load that meets every objective, well below the load at which errors explode.
- Stating capacity without its conditions. "The system handles 1,500 users" means nothing without the request mix, data volume, server sizes and objectives.
- Assuming linear scaling: multiplying the one-instance result instead of measuring several sizes.
- Changing several things between runs, such as instance count and code version, so a change in capacity cannot be explained.
- Testing scale-out against a small or nearly empty database, where the shared components never become the limit.
- Watching only the application servers. Without database and connection-pool metrics you see the plateau but not its cause.
The QA perspective
Capacity and scalability tests are planned with developers and operations (DevOps or SRE), because they need a production-like environment, monitoring and often a budget. The tester brings the objectives, the workload model and the step plan, and checks that environment and data are representative. Ask early: which forecast are we planning for, which resources may we change, and how quickly can capacity be added?
Report the capacity statement with its conditions, a table per configuration with efficiency and the first saturated resource, and a recommendation. Say plainly where the test environment differs from production. Keep the scripts and data so the test can be repeated after architecture changes, major releases or large data growth: capacity is a moving number.
Practice exercise
Read a vertical scaling result and size the next step
A product search service was tested on one instance at four sizes, with the same data and request mix. Its objective is p95 under 300 ms and errors under 1%. Judge how well it scales up and what capacity the forecast needs, then recommend the next test.
Service: product search, one instance, same data and request mix
Objective: p95 < 300 ms and errors < 1 %
vCPU Capacity (req/s) CPU at capacity Thread pool at capacity
2 250 95 % 38 of 64 busy
4 480 93 % 61 of 64 busy
8 610 58 % 64 of 64 busy
16 620 31 % 64 of 64 busy
Forecast peak next quarter: 900 req/s
Team policy: peak load stays at or below 80 % of tested capacity- Compute the scaling efficiency of each size relative to 2 vCPU.
- Find where scaling up stops paying off, and why.
- Compute the tested capacity the forecast needs under the team policy.
- Write a capacity statement and the next test.
Show the model answer
Efficiency relative to 2 vCPU: 4 vCPU = 480 ÷ (2 × 250) = 96%; 8 vCPU = 610 ÷ (4 × 250) = 61%; 16 vCPU = 620 ÷ (8 × 250) = 31%.
Scaling up pays off to 4 vCPU and then stops. At 8 and 16 vCPU the CPU is far from saturated (58% and 31%) but all 64 threads are busy: the fixed thread pool caps concurrent work, so the extra cores sit idle.
Needed tested capacity: 900 ÷ 0.8 = 1,125 req/s. The best single instance reached 620 req/s, so no tested size of one instance meets the forecast.
Statement: "Product search, one instance, current data and agreed mix: 480 req/s at 4 vCPU, about 620 req/s at 8 or 16 vCPU; above 4 vCPU the limit is the 64-thread pool, not CPU." Next: with the developers, enlarge the thread pool on 8 vCPU and repeat, and test scaling out with 4-vCPU instances. If scaling out were linear, three instances would give at most 3 × 480 = 1,440 req/s, enough for 1,125, so the plan would need four with a spare (N+1); measure it first, because a shared component may plateau as in the worked example.
Frequently asked questions
What is the difference between capacity testing and stress testing?
Capacity testing stops at the highest load where every objective still holds; stress testing goes beyond it on purpose to see how the system fails and recovers. Both can use a stepped ramp, but they read it differently: the answer of a capacity test is the last passing step, not the breaking point.
Is scalability testing the same as testing autoscaling?
No. An autoscaling test, as in spike testing, checks that new instances start quickly enough when load rises. A scalability test checks that those instances actually add capacity. A system can autoscale perfectly and still not scale, if every new instance waits on the same database.
Can I test capacity in a smaller environment and scale the result up?
Only with care. Per-instance capacity measured in a smaller environment is useful, but shared components and data volume do not grow in proportion, so a plateau may appear only at production size. State the differences in the report and confirm the key numbers in a production-sized environment before they drive a purchase or a launch.
Do I need a special tool for capacity testing?
No. The load tools from the earlier lessons, such as JMeter, k6, Gatling or Locust, can all raise load in steps. What differs is the plan: stepped load, the same run repeated per configuration, and server-side monitoring. The Grafana k6 documentation calls a test that raises load until the system fails a breakpoint test and notes that some people call it capacity testing. For capacity in the sense of this lesson, stop at the first step that breaks an objective; k6 can do this with a threshold set to abortOnFail.
References
- Certified Tester Performance Testing (CT-PT)ISTQB's specialist syllabus on performance testing: basic concepts, performance measurements, test activities and tasks, and tools.
- ISO/IEC 25010:2023 — Systems and software Quality Requirements and Evaluation (SQuaRE) — Product quality modelThe product quality model: functional suitability, performance efficiency, compatibility, interaction capability, reliability, security, maintainability and flexibility.
- Site Reliability Engineering: How Google Runs Production SystemsService level objectives, error budgets, monitoring the "four golden signals" and handling overload — the operational side of resilience.
- Load test types — Grafana k6 documentationDefinitions of the common load test types — smoke, average-load, stress, soak, spike and breakpoint — and what each one is meant to reveal.
Practise with Mutqan tools
Generate performance test inputs with realistic distributions: think times, request mixes, payload sizes and ramp profiles.
Generate concurrency test scripts (k6, JMeter JMX, Locust, Artillery, Node.js) with safe defaults for a target endpoint.
Generate large parameter datasets (users, tokens, ids, payloads) for k6, JMeter, Gatling and Locust load tests.
Generate large JSON arrays (thousands of records) from a template to test pagination, performance and parsers.
Run a small, safe benchmark against a public endpoint (bounded requests and concurrency) and get throughput and latency percentiles.
Go deeper
Your progress on this topic
Not started
Mark the topic complete when you have studied it and done the exercise.
Sign in to track your progress
Mark topics complete, continue where you left off and unlock specialisation exams.