Tools: How to Find Your API’s Breaking Point (Before Your Users Do) - Capacity Testing with JMeter

Tools: How to Find Your API’s Breaking Point (Before Your Users Do) - Capacity Testing with JMeter

Source: Dev.to

Capacity Testing an E-Commerce API with Apache JMeter ## Step 1: Organize Thread Groups ## Step 2: Load Configuration ## Step 3: Add Configuration Elements ## Step 4: Add HTTP Requests ## Step 5: Add Think Time ## Step 6: Add Listeners ## Step 7: Run Test and Observe ## Step 8: Example Result ## Final Thoughts When you build an API service, it’s crucial to know how many users or requests it can handle before things start breaking. This is where capacity testing comes in. What is Capacity Testing? Capacity testing identifies the maximum load your system can handle before performance degrades or errors appear. It helps detect bottlenecks and verify performance requirements under heavy load. Let’s say we have a REST API for an online store. We want to see how many requests it can handle before it starts failing. Option 1: Separate Thread Groups per endpoint Why? Because if one endpoint starts to degrade (high response time or errors), it can affect the throughput of other endpoints if tested together in the same group. Separate Thread Groups allow: Option 2: Mixed workload in one Thread Group In this example, we use Option 1. Number of Threads (Users) Set per Thread Group based on expected usage (e.g., browsing endpoints typically require more users than checkout). Ramp-Up Period Defines how quickly users are added. Short ramp-up creates spikes; longer ramp-up simulates gradual traffic growth (10 minutes). Loop Count and Duration Loop Count = Infinite, with a 10-minute test duration. Startup Delay Used for sequential Thread Groups to allow system recovery before applying the next load stage (the first Thread Group starts immediately). Increase users step-by-step to determine the capacity limit. 1. Add User-Defined Variables Create a User-Defined Variables element to store values you’ll use across your test plan: Now pass the created variables into the Thread Groups (example): 2. Add HTTP Request Defaults Add an HTTP Request Defaults element to set common request parameters, so you don’t have to repeat them in every HTTP Request sampler: Add an HTTP Request sampler to each Thread Group. Set the API endpoint and HTTP method (GET, POST, etc.) accordingly. Thread Group 1 → GET /products – browse products Thread Group 2 → GET /products/{id} – view product details Thread Group 3 → GET /products/search?q={searchPhrase} – search products by phrase Thread Group 4 → GET /orders/{orderId} – order details … and so on Current Test Plan structure: Think Time simulates real user pauses between actions. In other words, it simulates the time a real user spends "thinking," reading, or interacting with a page before making the next request. With think time, the test more accurately reflects real user behavior, helping identify bottlenecks under realistic traffic conditions. How to Implement in JMeter Use Timers such as Constant, Uniform Random, or Gaussian Random. Each request will randomly wait somewhere between 2 and 6 seconds Listeners in Apache JMeter are used to collect, display, and export test results. They help you analyze performance metrics during and after test execution. 1. Add Aggregate Report Aggregate Report – summary metrics (avg, min, max, throughput, error %). Useful for quick performance evaluation. 2. Add View Results Tree View Results Tree – debugging only (inspect requests and responses). 3. Add Backend Listener Backend Listener – send metrics to storage (InfluxDB) and analyze in Grafana for real-time dashboards and historical comparison. This approach allows you to: Using the Backend Listener with InfluxDB and Grafana provides a much more professional, production-ready analysis than basic JMeter listeners. Start with a low number of users and increase gradually. Monitor server resources (CPU, memory, database connections) while testing. Capacity is reached when: When throughput stops increasing, response times spike, or errors appear, this indicates the capacity limit for that endpoint. This example shows a 10-minute test with a 10-minute ramp-up to 100 users for the first endpoint: GET /products Since ramp-up equals test duration, users were added gradually throughout the entire test. Throughput increased steadily as concurrency grew. However, 500 errors appeared and increased with higher load, indicating endpoint degradation before reaching a stable throughput plateau. As a result, the capacity point could not be clearly determined, and a defect should be created for further investigation. This graph represents the response time metrics for the same 10-minute test. At the beginning of the test, response time is higher (~1 second) due to warm-up and cache initialization. After the initial minute, response time stabilizes around: Although latency remained relatively stable, the increasing error rate indicates system instability under higher concurrency. Capacity testing should be: Testing endpoints separately provides clearer insights and prevents one bottleneck from hiding another. Only after stabilizing individual endpoints should you move to mixed workload testing for full system capacity validation. If you’d like to dive deeper into other performance testing types and learn how to build a complete testing stack using JMeter, InfluxDB, and Grafana for real-time monitoring and analysis, you can explore the full course here: 👉 Performance Testing Fundamentals: From Basics to Hands-On (Udemy) Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse - Independent load for each endpoint - Clear identification of which endpoint is the bottleneck - Easier reporting and analysis - Multiple endpoints are executed together - Load is distributed based on user behavior percentages - The goal is to identify overall system capacity under real-world conditions - Makes it easy to adjust load or URLs without editing each Thread Group - Supports parameterization for multiple environments (dev, staging, production) - Keeps the test plan organized and maintainable - JMeter sends requests back-to-back, which is not realistic - The load pattern may overwhelm the system compared to real users - Metrics like response time, throughput, and error rate can be misleading - Place the Timer at the same hierarchical level as configuration elements in your Test Plan (above all Thread Groups). - When positioned here, the Timer applies globally to all Thread Groups. - This ensures consistent think time across all endpoints without repeating the Timer in each group - Constant Delay Offset = 2000 ms → every request waits at least 2 seconds before executing. - Random Delay Maximum = 4000 ms → adds a random delay between 0 and 4 seconds. - Monitor performance in real time - Store historical test data - Build dashboards for trend analysis - Compare multiple test runs - P50 ≈ 510 ms - P90 ≈ 540 ms - P95 ≈ 580 ms - Errors were present from the early stage of the test and increased with higher load - Although response times remained relatively stable, the growing error rate indicates system instability - A clear capacity point could not be determined - Further investigation and defect creation are required before continuing capacity validation - Incremental - Endpoint-specific - Data-driven