Load Testing with AI: Generating Realistic Performance Test Scenarios
A load test that hammers one endpoint at a constant rate proves almost nothing about production behavior. How to design scenarios that actually resemble real traffic, and generate them with AI instead of hand-writing k6 scripts from scratch.
"We load tested it" often means one endpoint, one constant request rate, run until it falls over. That answers a narrow question — the theoretical ceiling of that one endpoint in isolation — and says little about what actually happens in production, where traffic is bursty, users hit multiple endpoints in realistic sequences, and failure in one dependency cascades into others.
What a realistic scenario actually needs
| Dimension | Naive test | Realistic test |
|---|---|---|
| Traffic shape | Constant rate (e.g. flat 500 req/s) | Ramps and bursts matching real usage patterns — a spike at a known peak time, gradual ramp-up, not an instant step function |
| Request mix | Single endpoint hammered repeatedly | A realistic distribution across the endpoints users actually hit, in the sequences they actually hit them (browse, then add-to-cart, then checkout) |
| Data variety | Same request payload repeated | Varied, realistic payloads — cache hit rates and query plans behave very differently under repeated identical requests versus real variety |
| Dependency behavior | Downstream services assumed healthy | Includes scenarios where a downstream dependency is slow or failing, to test resilience patterns, not just raw throughput |
Worked example: generating a k6 scenario
Context: E-commerce API. Real traffic pattern from analytics: 60% of sessions only browse (GET /products, GET /products/{id}), 25% add to cart (+ POST /cart), 15% complete checkout (+ POST /checkout). Peak traffic hits 800 req/s over a 10-minute window during a sale, ramping up over 2 minutes and back down over 3.
Task: Write a k6 script modeling this scenario.
Constraints:
- Model the three user journeys as separate scenarios with the stated traffic split (60/25/15), not as independent unweighted endpoint hits.
- Use a realistic ramp (stages: ramp up over 2 min, sustain peak for 5 min, ramp down over 3 min) rather than an instant jump to peak load.
- Vary the product IDs and cart contents per virtual user using randomized realistic data, not the same fixed payload every request.
- Include checks (not just requests) that assert on response status and a latency threshold per endpoint, so a failing/slow response is visible in the test output, not just aggregate throughput.Once the baseline scenario works, a second useful prompt: "add a variant where the payment service responds with 5-second latency for 20% of requests — does checkout still complete gracefully, or does it cascade into timeouts elsewhere?" This is what actually validates the resilience layer (circuit breakers, timeouts, retries), not just raw capacity.
Reading the results correctly
- A test that passes at the target load but shows p99 latency climbing steadily throughout the run (not stabilizing) indicates a resource leak or unbounded queue, not headroom — extrapolate where it would fail, don't just check the pass/fail threshold at the end.
- Errors clustered at the ramp-up edge rather than steady-state often point to connection pool exhaustion or cold-start effects, not a genuine capacity problem — worth distinguishing before concluding the system "can't handle" the target load.
- A test that never fails at any load you try is testing something too easy — increase load until you find the actual breaking point, so you know the real ceiling and margin, not just that today's target is met.
Load testing and the production resilience layer (circuit breakers, bulkheads, graceful degradation) are two sides of the same reliability question — the Performance module covers generating scenarios that specifically stress the resilience patterns, not just raw throughput, since that's usually where production incidents actually originate.