# VoltTest — Complete Reference > Performance, load, and stress testing platform for PHP and Laravel developers. Powered by a Go engine scaling to 10M+ virtual users. ## Product Overview VoltTest is a cloud-based performance testing platform purpose-built for PHP and Laravel developers. It combines a high-performance Go engine with a native PHP SDK, so developers write tests in their own language — no JavaScript, no Java GUIs, no YAML configs. The platform runs in two modes: - **Headless mode**: Execute tests locally from the terminal (`php test.php` or `php artisan volttest:run`) - **Cloud mode**: Add `--cloud` to distribute load across dedicated cloud instances in 24 AWS regions, scaling to over 10 million concurrent virtual users ## Engine Performance - Go engine delivers 275 requests per second per virtual user - Each virtual user runs as a lightweight goroutine - Under 50 MB memory per 1,000 virtual users - Dedicated cloud instances per test — no shared infrastructure or noisy neighbors - Instances spin up automatically, generate load, and tear down on completion ## Features ### PHP SDK - Install via Composer: `composer require volt-test/php-sdk --dev` - Fluent PHP API for defining test scenarios - Multi-step scenario flows with weighted steps - Data providers for dynamic/parameterized payloads - Response extractors to chain data between steps - Configurable think times between actions - Response validation on status codes via validateStatus(); JSON and header values are read with the extractors rather than asserted per step ### Laravel Package - Install via Composer: `composer require volt-test/laravel-performance-testing --dev` - Artisan commands: `volttest:make` (generate test stubs), `volttest:run` (execute tests) - Automatic route discovery from your Laravel application - Session cookies handled automatically, one store per virtual user; CSRF token extraction is one call — `extractCsrfToken()` on the step that fetched the form - Supports both local and cloud execution ### Real-time Metrics Dashboard - Live updating during test execution - 30-second granularity, 1-second when zoomed to 5-minute window - Throughput (requests per second) - Response time percentiles: P50, P90, P95, P99 - Request success and error rates - Active virtual user count and ramp-up chart - Filter by scenario, step, or region ### Test Reporting - P50, P90, P95, P99 latency percentiles per run - Automatic error classification by type (timeout, connection reset, HTTP errors) - Request-level sampling for debugging individual requests - Run-to-run comparison with instant delta calculations - Per-scenario and per-step breakdown - Smart insights: auto-detect error spikes, P99 outliers, threshold breaches ### Distributed Cloud Testing - 24 AWS regions available; load split across several per run by weight - Per-region latency, throughput, and error rate metrics - Live geographic distribution map - Dedicated instances per test run - Automatic provisioning and teardown ## Pricing VoltTest uses a VU-hour billing model. 1 VU-hour = 1 virtual user running for 1 hour. ### Free Plan — $0/month - 500 concurrent virtual users - 5,000 VU-hours per month - Up to 10-minute test durations - 7-day data retention - No credit card required ### Solo Plan — $29/month ($23/month annual) - 5,000 concurrent virtual users - 50,000 VU-hours per month - Up to 30-minute test durations - 30-day data retention - Hard cap on VU-hours ### Pro Plan — $49/month ($39/month annual) - 25,000 concurrent virtual users - 250,000 VU-hours per month - Up to 60-minute test durations - 90-day data retention - Overage at $0.00065/VU-hour ### Business Plan — $149/month ($119/month annual) - 100,000 concurrent virtual users - 1,000,000 VU-hours per month - Up to 120-minute test durations - 365-day data retention - Overage at $0.00060/VU-hour ## Solutions ### PHP API Load Testing (https://volt-test.com/solutions/php-api-testing) - Load testing for REST and JSON APIs written in PHP — any framework, or none - Steps support GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS with arbitrary headers and a raw request body - A Content-Type header is required on any step that sends a body; step URLs are absolute - Values can be extracted from a JSON path, a response header, a cookie, a regex match or an HTML selector, then interpolated into a later step's URL, body or headers with ${variable} - Each virtual user runs the scenario independently with its own variables and, with automatic cookie handling enabled, its own cookie store - CSV data sources hand rows to virtual users sequentially, randomly, or uniquely (uniqueness preserved across nodes) - Load is either constant (virtual users + duration + optional ramp-up) or a staged profile; the two are mutually exclusive - Results report p95/p99, median, average, min/max response time, requests per second, and success rate - No GraphQL-specific support; the only per-step assertion in the PHP SDK is status-code validation ### Laravel Load Testing (https://volt-test.com/solutions/laravel-load-testing) - Composer package `volt-test/laravel-performance-testing`; requires Laravel 11, 12 or 13 on PHP 8.2+ and the pcntl extension (Unix only — not native Windows) - Exactly two Artisan commands: `volttest:make` scaffolds a test class, `volttest:run` executes it - `volttest:make --routes` reads the application's route table and writes one step per route, turning `{id}` segments into `${id}` variables; narrow with `--filter`, `--method`, `--auth` or `--select`. Route discovery does not exclude package routes, so Telescope/Horizon/debugbar appear unless filtered - Tests are plain classes in `app/VoltTests` implementing `VoltTest\Laravel\Contracts\VoltTestCase` with a single `define(VoltTestManager $manager): void` method - Session and cookie handling is automatic — every scenario enables it, so each virtual user holds its own Laravel session. CSRF is one line: `extractCsrfToken()` on the step that fetched the form, then `${csrf_token}` in the POST that follows - Steps take app-relative URLs (prefixed with the configured base URL) and accept PHP arrays as bodies, JSON- or form-encoded from the headers - `volttest:run` takes a class name, not a file path; `--cloud` runs the identical class on managed infrastructure; `--stage` and `--region` shape the load profile - Build gating is PHPUnit-only: extend `PerformanceTestCase` and assert with `assertVTP95ResponseTime`, `assertVTErrorRate`, `assertVTMinimumRPS`, `assertVTSuccessful`. The `volttest:run` command reports numbers but always exits successfully - Local runs print a console summary and write a JSON report to `storage/volttest/reports`; cloud runs report to the dashboard instead ### E-commerce Load Testing (https://volt-test.com/solutions/ecommerce-load-testing) - Rehearsing a sale spike against a storefront. Works with any storefront reachable over HTTP — WooCommerce, Magento, Shopware, PrestaShop, a custom Laravel build. No plugin required and none provided - Load shape is expressed as stages. **Each stage ramps to its target from wherever the previous stage ended** — a plateau is a stage whose target repeats the one before it. There is no hold(), spike() or soak() preset - Virtual user count is re-evaluated once per second; ramp-down retires the newest users first; a user added mid-ramp starts its scenario from step 1 - Weighted scenarios model the funnel: e.g. 70% browse-only, 30% browse-and-buy. Per-virtual-user cookie handling gives each shopper its own cart and session - CSV data sources in unique mode give each scenario run its own customer row. Rows are consumed per iteration, not per virtual user, and the file **wraps silently and reuses rows** once exhausted — size it above peak virtual users - **A request is scored successful when its status is 200–499.** Only 5xx and transport failures (timeout, reset, refused) count as failures. A 429 from a rate limiter, a 403 from a WAF, a 404 on a sold-out product and a 422 from a rejected checkout all count as successes unless the step carries an explicit status assertion. Attach validateStatus() to every step that matters - Does NOT detect overselling, double-charging or any cross-request consistency problem — responses are checked individually and no state is shared across virtual users - No payment-provider integration of any kind. The checkout call is an ordinary HTTP request; point it at a sandbox or test mode, never a live gateway - No JavaScript execution, so a headless or single-page storefront is exercised at its API layer only — no bundles, no client-side timings, no LCP/INP - Only test systems you own or are authorised to test (see https://volt-test.com/terms). All traffic carries `User-Agent: Volt-Test/` ## Comparisons ### VoltTest vs k6 - k6 uses JavaScript; VoltTest uses PHP — write tests in your application language - VoltTest offers a managed cloud; k6 Cloud is a separate paid product from Grafana Labs - VoltTest has native Laravel integration (Artisan commands, route discovery, per-virtual-user session handling, one-call CSRF token extraction); k6 has no framework integration - k6 has a larger ecosystem and extension library - k6 is open source; VoltTest is commercial with a free tier ### VoltTest vs JMeter - JMeter uses a Java GUI; VoltTest uses code-as-tests in PHP - VoltTest is cloud-native with managed infrastructure; JMeter requires self-hosted load generators - VoltTest's Go engine uses ~50 MB per 1,000 VUs; JMeter's Java runtime uses significantly more memory - JMeter has been around since 1998 with extensive community plugins - VoltTest provides instant cloud provisioning; JMeter requires manual infrastructure setup ## Quick Start ### PHP SDK ```php setVirtualUsers(100) ->setDuration('5m') ->setRampUp('30s'); $scenario = $test->scenario('Read users'); $scenario->step('Get Users') ->get('https://api.example.com/users') ->header('Accept', 'application/json') ->validateStatus('ok', 200); $result = $test->run(true); echo $result->getP95ResponseTime(); ``` Installed with: composer require volt-test/php-sdk Notes on the API: - The class is VoltTest\VoltTest; there is no TestManager class - The per-step status assertion is validateStatus(string $name, int $expected); there is no expectStatus() - Extraction methods are extractFromJson(), extractFromHeader(), extractFromCookie(), extractFromRegex() and extractFromHtml(); there is no extractJson() - Step URLs are absolute, and a Content-Type header is required on any step that sends a body - setVirtualUsers()/setDuration()/setRampUp() describe constant load; stage(duration, target) describes a staged profile, and the two are mutually exclusive ### Laravel ```bash composer require volt-test/laravel-performance-testing --dev php artisan volttest:make ApiTest php artisan volttest:run ApiTest --users=50 --duration=1m php artisan volttest:run ApiTest --cloud ``` The volttest:run argument is the test class name, not a file path. It also accepts a URL with --url for a direct one-off load test. ## About VoltTest VoltTest was founded by Islam A-Elwafa, a software engineer, after a Laravel API that passed all unit, feature, and browser tests failed in production under 200 concurrent users. The company first hired an external firm to run load tests, but the results could not be rerun in-house and the tooling lived outside PHP, so every new engineer had to learn a separate language and toolchain before writing a single test. He built VoltTest so PHP and Laravel teams could write load tests in PHP itself, in their own repository, with session cookies handled automatically and CSRF tokens and auth flows a single call away. Founder: Islam A-Elwafa (GitHub: https://github.com/elwafa, X: https://x.com/elwafa90, Email: islam@volt-test.com) Mission: Make load testing something every developer can write and understand, without depending on a specialist team or an external firm, with reports readable by everyone from a junior developer to the CTO. Vision: Support load testing in more languages beyond PHP over time, so teams on any stack can write load tests in the language they ship. ## Links - Website: https://volt-test.com - Features: https://volt-test.com/features - Pricing: https://volt-test.com/pricing - About (founder story): https://volt-test.com/about - Documentation: https://docs.volt-test.com - Laravel Docs: https://docs.volt-test.com/docs/laravel/laravel-installation - Solutions: https://volt-test.com/solutions - PHP API Load Testing: https://volt-test.com/solutions/php-api-testing - Laravel Load Testing: https://volt-test.com/solutions/laravel-load-testing - E-commerce Load Testing: https://volt-test.com/solutions/ecommerce-load-testing - Compare vs k6: https://volt-test.com/compare/volttest-vs-k6 - Compare vs JMeter: https://volt-test.com/compare/volttest-vs-jmeter - Compare vs LoadForge: https://volt-test.com/compare/volttest-vs-loadforge - GitHub: https://github.com/volt-test - Discord: https://discord.gg/BvQD6bptaD - X/Twitter: https://x.com/vt_developers - LinkedIn: https://www.linkedin.com/company/volt-test - Support: support@volt-test.com ## Glossary Standalone definition pages at https://volt-test.com/glossary — 20 load testing terms. ### Assertion URL: https://volt-test.com/glossary/assertion Also known as: Validation, Check An assertion is a check applied to a response during a load test — on status, body, or headers — that decides whether a request genuinely succeeded. A load test without assertions measures how fast a server can return bytes, not whether those bytes are right. This fails in a specific and expensive way: broken responses are usually faster than working ones, because the work never happened. ### Breakpoint Test URL: https://volt-test.com/glossary/breakpoint-test Also known as: Capacity Test, Breakpoint Testing A breakpoint test ramps load steadily upward until the system violates its targets or fails, in order to find the exact load at which capacity runs out. A breakpoint test exists to produce a single figure: the maximum load the system sustains while still meeting its targets. Everything about the design serves that output — a long, smooth, uninterrupted climb, with no plateaus or spikes to muddy where the curve turns. ### Concurrent Users URL: https://volt-test.com/glossary/concurrent-users Also known as: Concurrency, Simultaneous Users Concurrent users are the users active in a system at the same moment — in a load test, the virtual users holding an open session or an in-flight request. You set a virtual user count; you observe concurrency. The VU pool is only an upper bound. If half your VUs are sitting in think time at any given instant, actual request concurrency is roughly half the pool — and that gap widens the more realistic your think times are. ### Connection Pool URL: https://volt-test.com/glossary/connection-pool Also known as: Database Connection Pool, Pooling A connection pool is a fixed set of reusable open connections to a database or upstream service, shared between an application’s concurrent requests. Opening a database connection is expensive — a TCP handshake, authentication, session setup — and can easily cost more than the query that follows. A pool pays that cost once, keeps the connections open, and lends them out to requests that need one. ### Error Rate URL: https://volt-test.com/glossary/error-rate Also known as: Failure Rate, Error Percentage Error rate is the share of requests in a test that failed — connection errors, timeouts, unexpected status codes, or responses that failed an assertion. Error rate is the first number to read in any result, because it determines whether the rest of the numbers mean anything. A run reporting a 40 ms P95 and a 60% error rate is not a fast system; it is a system rejecting most of its traffic quickly. ### Latency URL: https://volt-test.com/glossary/latency Also known as: Network Latency, Time To First Byte Latency is the delay before a transfer begins — the time to get a request to the server and the first byte of the answer back, excluding transfer time. Latency is the wait before data starts flowing; response time is the whole round trip including the transfer. For a small JSON payload the two are nearly identical, which is why they get used interchangeably — and for a 5 MB download they are nothing alike. ### Load Profile URL: https://volt-test.com/glossary/load-profile Also known as: Load Pattern, Load Shape, Workload Model A load profile is the shape of load over time in a test — how many virtual users are active at each moment, from ramp-up through steady state to ramp-down. Two tests with an identical peak VU count can answer completely different questions depending on how they get there and how long they stay. The profile, not the peak, determines which failure modes a run can expose at all. ### P95 / P99 Percentiles URL: https://volt-test.com/glossary/percentiles-p95-p99 Also known as: P95, P99, 95th Percentile, 99th Percentile, Tail Latency A P95 of 800 ms means 95% of requests finished within 800 ms. P99 says the same at 99% — both describe the slow tail that an average conceals. Take 100 requests: 95 finish in 100 ms and 5 take 4 seconds. The mean is 295 ms, which sounds fine and describes not one single request in the set. The P95 is 4 seconds, which describes exactly what the unlucky users got. ### Ramp-Up URL: https://volt-test.com/glossary/ramp-up Also known as: Ramp Up, Ramp-Up Period Ramp-up is the period over which a test climbs from zero to its target load, adding virtual users gradually instead of starting all of them at once. Starting every virtual user in the same instant tests something no production system experiences. The first seconds of such a run measure cold caches, unwarmed JIT compilation, an empty connection pool, and autoscalers that have not reacted yet — all at once, and all attributed to your application. ### Requests Per Second (RPS) URL: https://volt-test.com/glossary/requests-per-second Also known as: RPS, QPS, Queries Per Second Requests per second is the number of HTTP requests a system handles each second — the most common concrete unit for expressing load test throughput. RPS counts individual HTTP requests. Transactions per second counts completed business operations, and one transaction usually spans several requests — a checkout might be six. Throughput is the general term for both, plus rates measured in bytes or messages. ### Response Time URL: https://volt-test.com/glossary/response-time Also known as: Round-Trip Time, Request Duration Response time is the total elapsed time from sending a request to receiving the complete response — everything the client waits for, network included. Response time is measured from the client’s point of view, which means it contains several things that are not your application code. When a number looks bad, breaking it into components usually shows where the time actually went. ### Saturation Point URL: https://volt-test.com/glossary/saturation-point Also known as: Knee Point, Saturation The saturation point is the load at which throughput stops rising even as more users arrive — the moment a resource runs out and queueing takes over. Plot achieved throughput and response time against active virtual users on the same time axis. Before saturation, throughput climbs in step with users and response time stays roughly flat. At saturation the two lines split: throughput flattens, and response time starts climbing. ### Scenario URL: https://volt-test.com/glossary/scenario Also known as: Test Scenario, User Journey A scenario is one complete user journey in a load test — an ordered sequence of steps that a virtual user executes from beginning to end. A scenario is more than a list of URLs, because the steps are connected. Step one logs in and the response carries a token; step two needs that token in a header; step three needs an order ID that only exists because step two succeeded. The scenario is what carries that state forward. ### Soak Test URL: https://volt-test.com/glossary/soak-test Also known as: Endurance Test, Longevity Test, Soak Testing A soak test holds a moderate, realistic load for hours or days to surface problems that only appear over time, such as memory leaks and pool exhaustion. Some defects are invisible at any load level and obvious at any duration. A handler that leaks 2 KB per request looks perfect in a ten-minute run and exhausts memory overnight. A log file that grows unrotated fills a disk on day three. A connection pool that leaks one connection in ten thousand requests takes hours to drain. ### Spike Test URL: https://volt-test.com/glossary/spike-test Also known as: Spike Testing, Surge Test A spike test applies a sudden, extreme jump in load and then removes it, to see whether a system absorbs the surge, sheds it cleanly, or falls over. Both push past normal load, but they differ in the axis they attack. A stress test raises the level of load until something gives. A spike test raises the rate of change — the peak may be entirely within capacity, yet arriving in five seconds instead of five minutes is what breaks things. ### Stress Test URL: https://volt-test.com/glossary/stress-test Also known as: Stress Testing A stress test pushes a system beyond its expected peak load to find where it degrades, what breaks first, and whether it recovers once the load drops. A load test asks whether the system meets its targets at expected load. A stress test asks what happens when it doesn’t. The difference is intent: a load test is a pass-or-fail check against a known number, while a stress test is an exploration of the region past that number, where the answer is not known in advance. ### Think Time URL: https://volt-test.com/glossary/think-time Also known as: Wait Time, Pacing Think time is the pause a virtual user takes between steps to imitate a real person reading, typing, or deciding before making the next request. A virtual user with no think time sends its next request the microsecond the previous response lands. That is not a user; that is a benchmark loop. It produces request rates no real population generates and a traffic pattern with none of the natural spacing that lets caches, pools, and queues recover between hits. ### Thread Group URL: https://volt-test.com/glossary/thread-group Also known as: Thread Group JMeter A thread group is JMeter’s unit of load: a named pool of threads that each run the same request sequence, with its own user count, ramp-up, and loop count. Thread group is Apache JMeter vocabulary, and it is the most widely recognised name for the concept because JMeter dominated load testing for well over a decade. In JMeter a test plan contains one or more thread groups, and every thread inside a group simulates one user running the samplers beneath it. ### Throughput URL: https://volt-test.com/glossary/throughput Also known as: Transaction Rate Throughput is the rate of work a system completes over time — usually requests, transactions, or bytes per second, measured at the completing end. You configure virtual users and think time; the system decides the throughput. This is the most common misreading of a load test result — treating a throughput figure as the load that was applied rather than the work that got done. ### Virtual Users (VUs) URL: https://volt-test.com/glossary/virtual-users Also known as: VU, VUs, Virtual User A virtual user is a simulated client that runs a test scenario end to end, independently and in parallel with every other virtual user in a test. A load generator creates a pool of virtual users and hands each one a copy of the scenario — the ordered list of requests that represents a single user journey. Each VU walks its own copy of that script: it opens its own connection, keeps its own cookies and extracted variables, and only moves to the next step once the previous one has returned. ## Blog ### How to Load Test Laravel Applications: Tools, Setup, and Real Results URL: https://volt-test.com/blog/laravel-load-testing Published: 2026-07-13 Keywords: laravel load testing, how to load test laravel, laravel performance testing, laravel stress testing, load test laravel api, laravel load testing tools, laravel concurrent users, laravel csrf load test, laravel sanctum load test, pest stressless vs volttest, k6 laravel, volttest php sdk # How to Load Test Laravel Applications: Tools, Setup, and Real Results More than seven years ago, I shipped a Laravel API that passed every unit test, every feature test, and every browser test I threw at it. The staging environment ran fine. Code review was clean. I deployed on a Friday afternoon, and by Monday morning, the app was returning 502s under 200 concurrent users. The database connection pool was exhausted. File-based sessions were creating lock contention. A queued job that ran fine in isolation was stacking up 4,000 pending jobs because the worker couldn't keep pace with incoming requests. None of these problems showed up in testing because I'd never tested with more than one user at a time. The company's first answer was to hire an external firm to run the load tests. The results were useful, but they arrived as a report from people who didn't know our codebase, and we couldn't rerun them after every change. So we brought load testing in-house with tools like k6, and got familiar with them ourselves. That exposed the real cost: the tooling lived outside PHP, so every new engineer we hired had to learn a separate language and toolchain before they could write a single test. With VoltTest, a PHP team goes from zero to a working load test in about two hours at most, because there's nothing new to learn. That experience is why I built [VoltTest](https://docs.volt-test.com), and it's why I'm writing this guide. Laravel load testing isn't optional if you're running anything beyond a personal project. This guide covers why Laravel apps fail under load, how the available tools compare, and how to set up and run real load tests using PHP: no JavaScript, no Python, no context-switching. TL;DR: Laravel load testing catches failures that unit and feature tests miss: database bottlenecks, session contention, queue backlogs. VoltTest lets you write load tests in PHP, handles CSRF and cookies automatically, integrates with PHPUnit for CI/CD gating, and scales from local runs to thousands of concurrent users in the cloud. This guide walks through the complete setup. ![Load test Laravel in pure PHP with VoltTest: CSRF, auth flows and queues handled, with PHPUnit gates for CI/CD](/img/laravel-load-testing-og.png) ## What Breaks in Laravel Under Load Laravel is optimized for developer productivity, not raw throughput. That's a deliberate trade-off, and a fine one, as long as you know where the framework's abstractions become bottlenecks under concurrent traffic. Laravel performance testing reveals bottlenecks that are invisible at low traffic. Here's what I've seen break in production, in order of how often it catches people off guard: ### Database: The First Wall You Hit Eloquent makes database access effortless, which is exactly why it becomes a problem under load. The patterns that work fine for 10 users collapse at 500: - **N+1 queries**: a `foreach` loop that fires 200 individual SELECTs instead of one eager-loaded query. At 100 concurrent users, that's 20,000 queries per second hitting your database. - **Missing indexes**: a `WHERE` clause on an unindexed column scans the full table. Fast at 1,000 rows, catastrophic at 1,000,000. - **Connection pool exhaustion**: PHP opens and closes database connections per-request. Under sustained load, the connection churn can exceed your database's `max_connections` limit, causing new requests to queue or fail. ### Sessions and Authentication File-based sessions (Laravel's default) use file locks. When multiple requests hit the same session (AJAX-heavy pages, SPA polling), they serialize instead of running in parallel. I've seen P95 response times jump from 50ms to 3 seconds just from session lock contention. CSRF token verification adds per-request overhead that's invisible at low traffic but measurable at scale. Sanctum token lookups hit the database on every authenticated request. That's fine at 50 RPS, but potentially a bottleneck at 500. ### Queues and Jobs Your queue workers have a fixed throughput. If incoming jobs arrive faster than workers can process them, the queue grows indefinitely. Load testing reveals whether your worker count matches your actual job generation rate, something you can't determine from unit tests. I've seen a notification system that dispatched 3 jobs per user action (email, Slack, database notification) overwhelm a 2-worker Horizon setup at just 100 concurrent users. The fix was simple (more workers, batching), but the problem only surfaced under load. ### PHP-FPM Worker Saturation Each PHP-FPM worker handles one request at a time. When all workers are busy, new requests queue at the web server level. The default `pm.max_children = 5` on many development setups is nowhere near enough for production traffic. Load testing tells you exactly how many workers you need, and whether switching to [Laravel Octane](https://laravel.com/docs/octane) with its persistent workers would help. ## Laravel Load Testing Tools Compared There's no shortage of load testing tools, but most of them aren't built with PHP or Laravel in mind. Here's an honest comparison of the options a Laravel developer is likely to consider: | Feature | VoltTest | k6 (Grafana) | Pest Stressless | LoadForge | |---|---|---|---|---| | **Test language** | PHP | JavaScript | PHP (wraps k6) | Python (Locust) | | **Install** | `composer require` | Binary download | `composer require` | SaaS / pip | | **Laravel CSRF handling** | Built-in `extractCsrfToken()` | Manual JS parsing | No | Manual Python parsing | | **Cookie/session management** | `autoHandleCookies()` | Manual | No | Manual | | **Multi-step scenarios** | Yes (chained steps with data extraction) | Yes | No (single URL only) | Yes | | **Artisan commands** | `volttest:make`, `volttest:run` | N/A | `pest stress` | N/A | | **PHPUnit integration** | Native (`PerformanceTestCase` + assertions) | No | Via Pest expectations | No | | **Route discovery** | `--routes` flag auto-generates tests | No | No | No | | **Data-driven (CSV)** | Yes (`unique`, `sequential`, `random` modes) | Yes | No | Yes | | **Cloud scaling** | Built-in (30+ regions) | Grafana Cloud k6 | No | Built-in | | **P95/P99 metrics** | Yes | Yes | Yes (via k6) | Yes | | **Staged load profiles** | Yes (spike, stress, soak patterns) | Yes | No (fixed concurrency) | Yes | | **Protocols supported** | HTTP only | HTTP, WebSocket, gRPC, browser | HTTP only | HTTP, plus any Python client | | **Per-step assertions** | Status code only | Arbitrary JS checks | Pest expectations (single URL) | Arbitrary Python | | **Maturity / ecosystem** | New (2025) | Large, Grafana-backed | Built on k6 | Established platform | ### When to Use Each Tool **VoltTest** is the right choice when your team writes PHP, you want tests version-controlled alongside your Laravel codebase, and you need multi-step scenarios with CSRF/auth handling without leaving the PHP ecosystem. It's the only tool with native Laravel Artisan integration and PHPUnit assertions for CI/CD gating. **k6** is excellent if your team is already invested in the Grafana observability stack or prefers JavaScript. Its Go-based engine is fast, and Grafana Cloud k6 scales well. [Laravel.com benchmarked it at 17,000 RPS](https://laravel.com/blog/k6-load-testing-on-laravel-cloud) against Laravel Cloud. But you'll write tests in JavaScript, not PHP — [the full comparison is here](/compare/volttest-vs-k6). **Pest Stressless** is perfect for quick single-URL smoke tests (`./vendor/bin/pest stress example.com --concurrency=5`). It wraps k6 under the hood and integrates with Pest's expectation API. But it can't chain requests, handle CSRF tokens, or simulate multi-step user flows. It's a quick-check tool, not a load testing solution. **LoadForge** works well for teams comfortable with Python/Locust who want a managed cloud platform. Its Laravel-specific guides are solid, but you write tests in Python. ([VoltTest vs LoadForge](/compare/volttest-vs-loadforge).) **Where VoltTest is the weaker choice:** it speaks HTTP and nothing else, so it can't drive a WebSocket, gRPC or queue workload — k6 can. Its only per-step assertion is the status code, so if you need to assert on response bodies mid-scenario, k6's checks are more expressive. And it's the newest tool in this table, with a correspondingly smaller ecosystem and shorter track record. ## Step-by-Step: Load Testing Laravel with VoltTest Everything below uses the [Laravel package](/solutions/laravel-load-testing) — Artisan commands, route scaffolding and session handling included. Let me walk through how I set up load testing for a Laravel application, from install to results. ### Install the Laravel Package ```bash composer require volt-test/laravel-performance-testing --dev php artisan vendor:publish --tag=volttest-config ``` This gives you Artisan commands, automatic CSRF handling, cookie management, and PHPUnit integration. The core [VoltTest PHP SDK](https://docs.volt-test.com/docs/introduction) is pulled in as a dependency. ### Create Your First Test ```bash php artisan volttest:make LoginTest ``` This scaffolds `app/VoltTests/LoginTest.php`. Here's a complete login flow that handles CSRF tokens automatically: ```php title="app/VoltTests/LoginTest.php" target('http://localhost:8000'); $scenario = $manager->scenario('Login Flow'); // Step 1: Load login page, extract CSRF token $scenario->step('Get Login Page') ->get('/login') ->expectStatus(200) ->extractCsrfToken(); // Step 2: Submit login with extracted token // Cookies are handled automatically, no manual session management $scenario->step('Submit Login') ->post('/login', [ '_token' => '${csrf_token}', 'email' => 'user@example.com', 'password' => 'password', ]) ->expectStatus(302) ->thinkTime('1s'); // Step 3: Verify authenticated access $scenario->step('Load Dashboard') ->get('/dashboard') ->expectStatus(200); } } ``` `extractCsrfToken()` reads the `_token` hidden input from the HTML response and stores it as `${csrf_token}` for subsequent steps. Cookies, including the `laravel_session` cookie, are passed between steps automatically. No manual header juggling. ### Run the Test ```bash php artisan volttest:run LoginTest --users=50 --duration=1m ``` For more control over how users are added over time, use staged load profiles: ```bash php artisan volttest:run LoginTest --users=50 --duration=1m --ramp-up=15s ``` Or define stages directly in your test for spike or stress patterns: ```php public function define(VoltTestManager $manager): void { $manager->target('http://localhost:8000'); // Ramp up, hold, spike, recover, ramp down $manager->stage('1m', 50); // Ramp to 50 VUs $manager->stage('5m', 50); // Hold steady $manager->stage('10s', 200); // Spike to 200 $manager->stage('2m', 200); // Hold spike $manager->stage('1m', 0); // Ramp down $scenario = $manager->scenario('Login Flow'); // ... steps as above } ``` See the [load profiles guide](https://docs.volt-test.com/docs/load-profiles) for spike, stress, soak, and step-up patterns. ## Testing Authentication Flows Under Load Authentication is where most load testing tools struggle with Laravel. CSRF tokens, session cookies, and Sanctum tokens all require extracting values from responses and passing them to subsequent requests. VoltTest handles both web and API authentication patterns. ### Web Routes: CSRF + Session Cookies For traditional Laravel web routes (Blade forms, Inertia, Livewire), VoltTest automatically handles the `laravel_session` cookie and provides `extractCsrfToken()`: ```php $scenario = $manager->scenario('Registration Flow') ->dataSource('users.csv', 'unique'); $scenario->step('Registration Page') ->get('/register') ->expectStatus(200) ->extractCsrfToken() ->thinkTime('3s'); $scenario->step('Submit Registration') ->post('/register', [ '_token' => '${csrf_token}', 'name' => '${name}', 'email' => '${email}', 'password' => '${password}', 'password_confirmation' => '${password}', ]) ->expectStatus(302); $scenario->step('Verify Dashboard Access') ->get('/dashboard') ->expectStatus(200); ``` Each virtual user gets unique credentials from the CSV file, so sessions don't collide. ### API Routes: Sanctum Token Auth For API endpoints using Laravel Sanctum or Passport, extract the token from the JSON response: ```php $scenario = $manager->scenario('API Auth Flow'); $scenario->step('Login API') ->post('/api/login', [ 'email' => 'user@example.com', 'password' => 'password', ], ['Content-Type' => 'application/json', 'Accept' => 'application/json']) ->expectStatus(200) ->extractJson('token', 'data.token'); $scenario->step('Get User Profile') ->get('/api/user') ->header('Authorization', 'Bearer ${token}') ->header('Accept', 'application/json') ->expectStatus(200) ->extractJson('user_id', 'data.id'); $scenario->step('Update Profile') ->put('/api/user/${user_id}', [ 'name' => 'Updated Name', ], ['Content-Type' => 'application/json', 'Authorization' => 'Bearer ${token}']) ->expectStatus(200); ``` The `extractJson('token', 'data.token')` call captures the token from the login response and makes it available as `${token}` in all subsequent steps. This works with any JSON structure: nested paths like `data.user.api_token` and array indexing like `data[0].token` are both supported. ## Testing Queues, Jobs, and Broadcasting Under Load Authentication isn't the only Laravel-specific concern. Queue-heavy applications (and most non-trivial Laravel apps dispatch jobs) need load testing that exercises the full request-to-job pipeline. The pattern is straightforward: your load test hits endpoints that dispatch jobs, and you monitor whether the queue keeps up or falls behind. VoltTest doesn't test queue workers directly (that's a monitoring concern; [Laravel Horizon](https://laravel.com/docs/horizon) and [Pulse](https://laravel.com/docs/pulse) handle it). But it does tell you how fast your application *generates* jobs under concurrent load, which is the data you need to size your worker pool. Here's a real scenario: an e-commerce app where every order dispatches three jobs: a confirmation email, an inventory update, and a webhook notification to a fulfillment service. ```php title="app/VoltTests/OrderLoadTest.php" target('http://localhost:8000'); $scenario = $manager->scenario('Order Flow') ->dataSource('customers.csv', 'unique'); $scenario->step('Login API') ->post('/api/login', [ 'email' => '${email}', 'password' => '${password}', ], ['Content-Type' => 'application/json']) ->expectStatus(200) ->extractJson('token', 'data.token'); $scenario->step('Add to Cart') ->post('/api/cart', [ 'product_id' => 42, 'quantity' => 1, ], [ 'Authorization' => 'Bearer ${token}', 'Content-Type' => 'application/json', ]) ->expectStatus(200) ->thinkTime('2s'); $scenario->step('Place Order') ->post('/api/orders', [ 'payment_method' => 'card_test', 'shipping_address_id' => 1, ], [ 'Authorization' => 'Bearer ${token}', 'Content-Type' => 'application/json', ]) ->expectStatus(201); } } ``` Run this at 100 concurrent users for 5 minutes and then check Horizon: how many pending jobs accumulated? If the queue depth grew steadily throughout the test, your workers can't keep up with the job generation rate at that concurrency level. The fix is usually more workers, job batching, or moving non-critical jobs (analytics, logging) to a separate lower-priority queue. This is the kind of problem that never appears in unit or feature tests. It only surfaces when the *rate* of job dispatch exceeds worker throughput, which requires concurrent load to trigger. ## Interpreting Your Results: P95, P99, and What They Mean When I run a load test, the output looks like this: ```text Test Metrics Summary: =================== Duration: 60.003s Total Reqs: 12847 Success Rate: 99.92% Req/sec: 214.11 Success Requests: 12837 Failed Requests: 10 Response Time: ------------ Min: 8.21ms Max: 1.247s Avg: 94.31ms Median: 72.18ms P95: 182.65ms P99: 341.20ms ``` Here's what matters and what doesn't: | Metric | What It Tells You | When to Worry | |---|---|---| | **Success Rate** | Percentage of non-error responses | Below 99% under expected load | | **Req/sec (RPS)** | Actual throughput | Below your expected peak traffic | | **P95** | 95% of users experience this latency or better | Above 200ms for API routes, 500ms for web pages | | **P99** | The worst 1% of user experiences | More than 3x the P95 (indicates intermittent bottlenecks) | | **Avg** | Statistical average that hides outliers | Avoid making decisions on this alone | | **Max** | Single worst response | Above 5 seconds (timeouts incoming) | **The P95/P99 gap is your most important diagnostic signal.** If P95 is 180ms but P99 is 2 seconds, you have intermittent slowdowns, usually database lock contention, garbage collection pauses, or a slow external API call that occasionally blocks. If P95 and P99 are close together, your performance is consistent. **Run at increasing VU counts** (50, 100, 200, 500) and plot P95 against VU count. The inflection point, where P95 starts climbing sharply, is your app's capacity ceiling. Everything above that line requires optimization or horizontal scaling. ### What "Good" Looks Like for Laravel These aren't universal rules; your thresholds depend on app complexity, database size, and infrastructure. But as starting benchmarks from my experience testing dozens of Laravel apps: | Endpoint Type | Target P95 | Target Success Rate | Notes | |---|---|---|---| | Static/cached API | < 50ms | > 99.9% | Redis or response cache should absorb most of the work | | Authenticated API (CRUD) | < 200ms | > 99.5% | Database queries are the usual bottleneck | | Web pages (Blade/Inertia) | < 500ms | > 99% | Includes view rendering and asset pipeline overhead | | Complex operations (reports, exports) | < 2s | > 95% | Heavy queries are expected, so set realistic thresholds | If your numbers are significantly worse than these baselines under moderate load (50-100 VUs), you likely have a query optimization issue, not an infrastructure one. Start with `php artisan telescope` or query logging before scaling hardware. ## Automating Load Tests in CI/CD Performance regressions are silent: they don't trigger test failures unless you wire up assertions. VoltTest's PHPUnit integration turns load tests into automated quality gates. ### PHPUnit Performance Assertions ```php title="tests/Performance/ApiLoadTest.php" runVoltTest(new LoginTest(), [ 'virtual_users' => 30, 'duration' => '30s', ]); // Fail the build if performance degrades $this->assertVTSuccessful($result, 99.0); $this->assertVTP95ResponseTime($result, 200); $this->assertVTP99ResponseTime($result, 500); $this->assertVTMinimumRPS($result, 100); $this->assertVTErrorRate($result, 1.0); } } ``` Available assertions: | Assertion | What It Checks | |---|---| | `assertVTSuccessful($result, 99.0)` | Success rate ≥ 99% | | `assertVTP95ResponseTime($result, 200)` | P95 latency ≤ 200ms | | `assertVTP99ResponseTime($result, 500)` | P99 latency ≤ 500ms | | `assertVTMinimumRPS($result, 100)` | Throughput ≥ 100 req/s | | `assertVTErrorRate($result, 1.0)` | Error rate ≤ 1% | | `assertVTAverageResponseTime($result, 150)` | Avg latency ≤ 150ms | | `assertVTMedianResponseTime($result, 100)` | Median latency ≤ 100ms | ### GitHub Actions Workflow Here's a working workflow that runs load tests on every pull request and fails the build on performance regression: ```yaml title=".github/workflows/load-test.yml" name: Performance Tests on: pull_request: branches: [main] jobs: load-test: runs-on: ubuntu-latest services: mysql: image: mysql:8.0 env: MYSQL_DATABASE: testing MYSQL_ROOT_PASSWORD: password ports: - 3306:3306 options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 redis: image: redis:7 ports: - 6379:6379 steps: - uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: '8.3' extensions: pdo_mysql, redis, pcntl coverage: none - name: Install dependencies run: composer install --no-interaction --prefer-dist - name: Prepare environment run: | cp .env.testing .env php artisan key:generate php artisan migrate --seed - name: Start application server run: php artisan serve --host=127.0.0.1 --port=8000 & env: DB_CONNECTION: mysql DB_HOST: 127.0.0.1 DB_PORT: 3306 DB_DATABASE: testing DB_USERNAME: root DB_PASSWORD: password - name: Wait for server run: | for i in $(seq 1 30); do curl -s http://127.0.0.1:8000 > /dev/null && break sleep 1 done - name: Run performance tests run: vendor/bin/phpunit --testsuite=Performance env: VOLTTEST_BASE_URL: http://127.0.0.1:8000 ``` Add the performance test suite to your `phpunit.xml`: ```xml tests/Performance ``` Now every PR runs a load test. If P95 latency exceeds 200ms or the success rate drops below 99%, the build fails, and the developer sees exactly which metric regressed. ## Scaling to Thousands of Users with VoltTest Cloud Local testing is limited by your machine's hardware. My laptop can drive a few hundred virtual users comfortably; beyond that, the load generator itself becomes the bottleneck. VoltTest Cloud runs your tests on managed infrastructure across 30+ AWS regions. The code doesn't change. You add one line: ```php $manager->cloud(); ``` Or from the CLI: ```bash php artisan volttest:run LoginTest --users=5000 --duration=5m --cloud ``` For multi-region distribution: ```php $manager->cloud(); $manager->regions([ 'us-east-1' => 60, // 60% of VUs in Virginia 'eu-west-1' => 40, // 40% in Ireland ]); ``` The cloud dashboard shows real-time metrics (RPS, latency percentiles, error rates, and per-step breakdowns) as the test runs. Results are stored for comparison across test runs. Try VoltTest Cloud Free: Run distributed load tests at scale without managing infrastructure — 500 VUs free, no credit card. ## What to Do Next 1. **Install the package**: `composer require volt-test/laravel-performance-testing --dev` 2. **Test your login flow**: it's the most common bottleneck and the easiest to test first 3. **Run at increasing VU counts**: 10, 50, 100, 200. Watch where P95 inflects 4. **Add PHPUnit assertions**: wire performance tests into your CI pipeline so regressions never reach production 5. **Try cloud mode**: when you need thousands of concurrent users or multi-region testing Laravel performance testing isn't about generating impressive throughput numbers. It's about knowing, before your users tell you, whether your app handles the traffic you expect. ## Learn More - [Laravel Package Documentation →](https://docs.volt-test.com/docs/laravel/laravel-installation) - [VoltTest PHP SDK Documentation →](https://docs.volt-test.com/docs/introduction) - [Load Testing Laravel with PHPUnit (deep dive) →](/blog/laravel-load-testing-with-phpunit) - [Load Profiles: Spike, Stress, Soak Patterns →](https://docs.volt-test.com/docs/load-profiles) - [PHP Load Testing Guide →](/blog/php-load-testing) - [How to Stress Test PHP Applications: Bottlenecks and Breaking Points →](/blog/php-stress-testing-tool) --- GitHub: [volt-test/php-sdk](https://github.com/volt-test/php-sdk) | [volt-test/laravel-performance-testing](https://github.com/volt-test/laravel-performance-testing) Follow updates on X: [@VT_Developers](https://x.com/VT_Developers) --- ### PHP Load Testing: How to Load Test PHP Applications URL: https://volt-test.com/blog/php-load-testing Published: 2026-06-19 Keywords: php load testing, php load testing tools, load testing php, php performance testing, php performance testing tool, performance testing php, php load test # How to Load Test PHP Applications PHP powers roughly [77% of all websites with a known server-side language](https://w3techs.com/technologies/details/pl-php) — yet most PHP developers ship code without ever running a load test. The app works fine in development, handles a handful of users on staging, and then crumbles when real traffic arrives. Load testing catches that gap *before* your users do: it verifies that your application handles the traffic you actually expect, not just the traffic your laptop can produce. This guide covers what load testing means for PHP, how to pick the right tool, how the main options compare, and how to write and run a real multi-step load test — on plain PHP or Laravel — in minutes. TL;DR: PHP load testing verifies your application handles real traffic levels — not just your laptop's dev server. VoltTest lets you write load tests in PHP, install via Composer, and scale from local runs to 10M+ concurrent users in the cloud. This guide covers tool selection, comparison, and step-by-step implementation for both plain PHP and Laravel. ![PHP load testing results showing 99.94% success rate, 540 requests per second, and 128ms P95 latency](/img/php-load-testing-og.png) ## What Is Load Testing? Load testing simulates a realistic number of concurrent users hitting your application to verify it handles normal and peak traffic without degrading. It answers questions like: Can the app serve 500 users at once without response times climbing past 200ms? Does the database connection pool hold up under sustained load? Do sessions and caches behave correctly when 100 users are active simultaneously? It's easy to mix up the different flavors of performance testing (we break these down in detail in our [performance testing types](/blog/performance-testing-types) guide): - **Load testing** — verify the app handles an *expected* level of traffic (e.g. 500 concurrent users for 10 minutes). - **Stress testing** — push *past* expected traffic to find the breaking point. (For a hands-on guide, see [PHP Stress Testing Tool](/blog/php-stress-testing-tool).) - **Benchmarking** — measure raw throughput of a single endpoint (`ab -n 1000 -c 50`), without modeling realistic user flows. Load testing is the baseline: it tells you whether your app can handle Tuesday at 2pm, not just whether it survives Black Friday. ### Why Load Testing Matters Specifically for PHP PHP's request lifecycle introduces concerns that don't exist in long-running runtimes like Node.js or Go: - **Process-per-request model** — each request bootstraps the framework. Under load, this means OPcache warming, autoloader performance, and memory limits all become bottlenecks. - **Database connection pooling** — PHP doesn't keep connections alive across requests by default. Under load, the connection churn can exhaust your database's `max_connections`. - **Session handling** — file-based sessions create lock contention when multiple requests hit the same user session. Load testing surfaces this before production does. - **External service timeouts** — a payment gateway that responds in 200ms under light load might take 2 seconds when 50 requests queue up. Your timeout settings need to account for this. ## When Should You Load Test a PHP Application? You don't need to load test every commit. But you should run one: - **Before major releases** — especially ones that change database queries, caching, or authentication flows. - **After infrastructure changes** — new server, PHP version upgrade, switching from Apache to Nginx/FrankenPHP, moving to containers. - **Before expected traffic spikes** — product launches, marketing campaigns, seasonal peaks. - **When adding heavy features** — file uploads, report generation, real-time notifications, anything that changes how the app uses CPU or I/O. - **In CI/CD** — catch performance regressions automatically. VoltTest's [PHPUnit integration](/blog/laravel-load-testing-with-phpunit) makes this straightforward. ## What Should You Look For in a PHP Load Testing Tool? Not every load testing tool fits a PHP team. Before picking one, check it against these criteria: - **PHP-native test definition** — can you write tests in PHP and install via Composer, or do you have to learn a separate language and toolchain? - **Realistic multi-step scenarios** — real users don't just hit one endpoint. They browse, log in, add to cart, and check out. The tool should chain requests, pass data between steps, and handle cookies/tokens. - **Concurrent virtual users** — true concurrency, not sequential requests fired in a loop. - **Percentile metrics** — averages hide problems. You need P95 and P99 latency to see what your slowest users experience. - **Data-driven testing** — CSV data sources so each virtual user gets unique credentials, avoiding session contention. - **Scalability** — local testing for development, cloud execution for production-scale validation. ## Which PHP Load Testing Tool Should You Use? Here's an honest comparison of the most common options: | Feature | VoltTest | Apache JMeter | k6 (Grafana) | Locust | Apache Bench | |---|---|---|---|---|---| | Write tests in | PHP | Java / XML GUI | JavaScript | Python | CLI flags | | Install via | Composer | Download JVM app | Install binary | pip install | Pre-installed (most OS) | | Laravel integration | Native package | None | None | None | None | | Multi-step scenarios | Yes | Yes | Yes | Yes | No | | Concurrent VUs (local) | Thousands | Hundreds | Thousands | Hundreds | Limited | | Cloud scaling | Built-in | DIY infrastructure | Grafana Cloud | DIY infrastructure | N/A | | P95/P99 metrics | Yes | Yes | Yes | Yes | No | | Data-driven (CSV) | Yes | Yes | Yes | Yes | No | | CI/CD integration | PHPUnit | Jenkins plugin | CLI | CLI | CLI | | Protocols supported | HTTP only | HTTP, JDBC, JMS, FTP, LDAP, TCP | HTTP, WebSocket, gRPC, browser | HTTP, plus any Python client | HTTP only | | Per-step assertions | Status code only | Full assertion library | Arbitrary JS checks | Arbitrary Python | None | | Maturity / ecosystem | New (2025) | Since 1998, large plugin ecosystem | Large, Grafana-backed | Mature Python project | Ships with Apache | - **Apache Bench (`ab`)** is useful for a quick one-off sanity check (`ab -n 1000 -c 50 http://localhost/api/health`), but it can't model user flows, extract tokens, or report percentile latencies. - **[JMeter](https://jmeter.apache.org/)** is the established enterprise option with broad protocol support, but its XML/GUI workflow is a steep learning curve for a team that just wants to validate their PHP API. We break the trade-offs down in [VoltTest vs JMeter](/compare/volttest-vs-jmeter). - **[k6](https://grafana.com/docs/k6/latest/)** is modern and well-documented, but you write tests in JavaScript — a context switch for a PHP team. See [how the two compare on a PHP stack](/compare/volttest-vs-k6). - **[Locust](https://locust.io/)** follows the same pattern but in Python. - **VoltTest** is built for PHP and Laravel teams: tests are written in PHP, installed with Composer, and executed by a Go engine that handles the concurrent load generation. It's the only option with a native Laravel package, Artisan commands, and PHPUnit integration. The trade-off is deliberate narrowness: it speaks HTTP only, its per-step assertion is the status code, and it's the youngest tool here. If you need to load test a message queue or a database directly, or assert on response bodies step by step, reach for JMeter or k6. ## How Do You Load Test a PHP Application with VoltTest? Let's write a real load test. The core SDK is framework-agnostic — it works with any PHP application. ### Install ```bash composer require volt-test/php-sdk ``` ### Basic Load Test — Single Endpoint Start simple: 50 concurrent users hitting an API endpoint for 30 seconds. ```php title="load-test.php" setVirtualUsers(50) ->setRampUp('10s') ->setDuration('30s'); $scenario = $test->scenario('Product Listing'); $scenario->step('Get Products') ->get('https://your-app.test/api/products') ->header('Accept', 'application/json') ->validateStatus('products_ok', 200); $test->run(true); ``` Run it: ```bash php load-test.php ``` The `setRampUp('10s')` gradually adds virtual users over 10 seconds instead of slamming the app with all 50 at once — this models realistic traffic, not a thundering herd. ### Multi-Step Load Test — Realistic User Flow Real users don't just hit one endpoint. Here's a load test that simulates browsing products, logging in, and placing an order — the same shape as a [storefront checkout rehearsal](/solutions/ecommerce-load-testing): ```php title="checkout-flow-test.php" setVirtualUsers(30) ->setRampUp('15s') ->setDuration('2m'); $scenario = $test->scenario('Browse → Login → Checkout') ->autoHandleCookies(); // Each VU gets a unique user from the CSV $scenario->setDataSourceConfiguration( new DataSourceConfiguration(__DIR__ . '/users.csv', 'unique', true) ); // Step 1: Browse products $scenario->step('List Products') ->get('https://your-app.test/api/products') ->header('Accept', 'application/json') ->extractFromJson('product_id', 'data[0].id') ->validateStatus('products_loaded', 200) ->setThinkTime('2s'); // Step 2: Log in and extract auth token $scenario->step('Login') ->post('https://your-app.test/api/login', '{"email":"${email}","password":"${password}"}') ->header('Content-Type', 'application/json') ->header('Accept', 'application/json') ->extractFromJson('token', 'data.token') ->validateStatus('login_ok', 200) ->setThinkTime('1s'); // Step 3: Add product to cart $scenario->step('Add to Cart') ->post('https://your-app.test/api/cart', '{"product_id":"${product_id}","quantity":1}') ->header('Authorization', 'Bearer ${token}') ->header('Content-Type', 'application/json') ->header('Accept', 'application/json') ->validateStatus('added_to_cart', 200) ->setThinkTime('2s'); // Step 4: Checkout $scenario->step('Checkout') ->post('https://your-app.test/api/checkout', '') ->header('Authorization', 'Bearer ${token}') ->header('Content-Type', 'application/json') ->header('Accept', 'application/json') ->validateStatus('checkout_ok', 201); $result = $test->run(true); echo "\n\nResults:\n"; echo "Total Requests: " . $result->getTotalRequests() . "\n"; echo "Success Rate: " . $result->getSuccessRate() . "%\n"; echo "RPS: " . $result->getRequestsPerSecond() . "\n"; echo "P95 Latency: " . $result->getP95ResponseTime() . "\n"; echo "P99 Latency: " . $result->getP99ResponseTime() . "\n"; ``` The CSV file supplies unique credentials so each virtual user logs in with different data — no session contention: ```csv title="users.csv" email,password user1@example.com,password123 user2@example.com,password123 user3@example.com,password123 ``` ## How Do You Load Test a Laravel Application? If you're on Laravel, the [dedicated Laravel package](/solutions/laravel-load-testing) adds Artisan commands, automatic CSRF handling, and PHPUnit integration on top of the core SDK. (See also: [Effortless Laravel Performance Testing with VoltTest](/blog/effortless-laravel-performance-testing-with-volt-test-php-sdk) for a deeper walkthrough.) ### Install ```bash composer require volt-test/laravel-performance-testing --dev php artisan vendor:publish --tag=volttest-config ``` ### Quick Load Test from the Command Line For a fast check, test a single URL directly from Artisan — no test class needed: ```bash php artisan volttest:run https://your-app.test/api/products --users=50 --duration=30s ``` This gives you the one-liner speed of Apache Bench but with real virtual-user concurrency and percentile metrics. ### Full Scenario Load Test Scaffold a test class: ```bash php artisan volttest:make CheckoutLoadTest ``` Define the scenario with CSRF token handling and data sources: ```php title="app/VoltTests/CheckoutLoadTest.php" target('http://localhost:8000'); $scenario = $manager->scenario('Web Checkout Flow') ->dataSource('users.csv', 'unique'); $scenario->step('Visit Shop') ->get('/shop') ->expectStatus(200) ->extractCsrfToken() ->thinkTime('2s'); $scenario->step('Add to Cart') ->post('/cart/add', [ '_token' => '${csrf_token}', 'product_id' => 1, 'quantity' => 1, ]) ->expectStatus(302) ->thinkTime('1s'); $scenario->step('Checkout Page') ->get('/checkout') ->expectStatus(200) ->extractCsrfToken() ->thinkTime('3s'); $scenario->step('Place Order') ->post('/checkout', [ '_token' => '${csrf_token}', 'email' => '${email}', ]) ->expectStatus(302); } } ``` Run it: ```bash php artisan volttest:run CheckoutLoadTest --users=100 --duration=2m ``` ### Load Testing in PHPUnit You can also run load tests inside your existing PHPUnit suite and fail the build when performance degrades: ```php title="tests/Performance/CheckoutLoadTest.php" runVoltTest(new VoltCheckout, [ 'virtual_users' => 50, ]); $this->assertVTSuccessful($result, 99); $this->assertVTP95ResponseTime($result, 200); $this->assertVTP99ResponseTime($result, 500); $this->assertVTErrorRate($result, 1); } } ``` ```bash vendor/bin/phpunit --testsuite Performance ``` This catches performance regressions in CI before they reach production. ## Data-Driven Load Testing with CSV Using a single test account for all virtual users creates unrealistic session contention. CSV data sources solve this: ```csv title="users.csv" email,password,name alice@example.com,secret123,Alice bob@example.com,secret123,Bob carol@example.com,secret123,Carol dave@example.com,secret123,Dave ``` In plain PHP, configure the data source on your scenario: ```php $scenario->setDataSourceConfiguration( new DataSourceConfiguration(__DIR__ . '/users.csv', 'unique', true) ); ``` In Laravel, use the shorthand: ```php $scenario = $manager->scenario('User Flow') ->dataSource('users.csv', 'unique'); ``` The iteration mode controls how rows are assigned to virtual users: | Mode | Behavior | |---|---| | `unique` | Each VU gets a different row. VUs > rows causes an error. | | `sequential` | VUs cycle through rows in order, wrapping around. | | `random` | Each VU gets a random row on each iteration. | Use `unique` for load tests where session isolation matters (login flows), and `sequential` or `random` for read-only endpoints where overlap is fine. ## Reading Your Load Test Results VoltTest output looks like this: ```text Performance Report: Checkout Flow Load Test ---------------------------------------------------------------------- Total Requests: 6000 Success Rate: 99.87% Requests/Sec (RPS): 198.42 Avg Latency: 94.31ms P95 Latency: 182.65ms P99 Latency: 341.20ms ---------------------------------------------------------------------- ``` What each metric tells you: - **Success Rate** — below ~99% means the app is dropping or erroring requests under this load level. Investigate error logs. - **Requests/Sec (RPS)** — your real-world throughput. If your expected peak is 200 RPS and the test shows 198, you're running at the limit with no headroom. - **Avg Latency** — useful as a baseline, but it masks outliers. An average of 94ms is meaningless if 1% of users wait 2 seconds. - **P95 Latency** — the response time 95% of requests complete within. This is your primary metric for user experience. - **P99 Latency** — the tail. If P99 is dramatically higher than P95, you have intermittent bottlenecks — likely database lock contention, garbage collection, or external service timeouts. When load testing, run the same scenario at increasing VU counts (50, 100, 200, 500) and watch how P95 and RPS change. The point where P95 starts climbing sharply is your capacity limit. ## What Are the Most Common PHP Load Testing Mistakes? A few mistakes make load test results misleading or useless: - **Testing on localhost** — your laptop is not production. Network latency, CPU, memory, and database all differ. Test against a staging environment that mirrors production hardware. - **No ramp-up** — slamming the app with all users at once tests a thundering herd, not real traffic. Use `setRampUp()` to add users gradually. - **Single test user** — every VU sharing one login causes session lock contention, which inflates latency. Use CSV data sources with unique users. - **Only testing the homepage** — the homepage is often cached and fast. Test the slow paths: search, checkout, report generation, admin dashboards. - **Running from the same machine as the app** — the load generator and the app compete for CPU and memory, distorting results. Run the test from a separate machine. - **Watching averages instead of P95/P99** — an average of 80ms with P99 of 3 seconds means 1 in 100 users is having a terrible experience. Always read the tail. ## Scaling Up with VoltTest Cloud Local testing is limited by your machine's resources — a laptop can drive a few hundred to a few thousand virtual users depending on the scenario complexity. For production-scale validation (10,000+ concurrent users, multiple regions), VoltTest Cloud runs your tests on managed infrastructure. The test code stays the same — just add the `--cloud` flag: ```bash php artisan volttest:run CheckoutLoadTest --users=5000 --duration=5m --cloud ``` Or in plain PHP, enable cloud mode with your API key: ```php $test->cloud('vt_YOUR_API_KEY'); ``` Try VoltTest Cloud Free: Run distributed load tests at scale without managing infrastructure — 500 VUs free, no credit card. ## Conclusion Load testing PHP applications doesn't require learning a new language or spinning up a complex infrastructure. With VoltTest, you write tests in PHP, install via Composer, and run them locally or at cloud scale. Start with a single endpoint, graduate to multi-step user flows, wire the tests into PHPUnit and CI, and monitor P95/P99 as load climbs. The goal isn't to generate impressive numbers — it's to know, with confidence, that your app handles the traffic you expect. ## Learn More - [PHP Stress Testing Tool: How to Stress Test PHP & Laravel Apps →](/blog/php-stress-testing-tool) - [Stress Testing Laravel Applications with VoltTest (Web UI Flow) →](/blog/stress-testing-laravel-with-volt-test-web-ui) - [Load Testing Laravel with PHPUnit →](/blog/laravel-load-testing-with-phpunit) - [Introducing VoltTest: The PHP-Native Load Testing SDK →](/blog/introducing-volt-test-php-load-testing) - [VoltTest Cloud Closed Beta: How to Get Access →](/blog/volt-test-cloud-closed-beta-open) - [VoltTest PHP SDK Documentation →](https://docs.volt-test.com/docs/introduction) --- ⭐ **Star the repository on GitHub:** [volt-test/php-sdk](https://github.com/volt-test/php-sdk) 💬 **Follow updates on X:** [@VoltTest](https://x.com/VT_Developers) --- --- ### VoltTest Cloud Closed Beta Is Now Open: How to Get Access URL: https://volt-test.com/blog/volt-test-cloud-closed-beta-open Published: 2026-06-12 Keywords: volt-test cloud, closed beta, cloud load testing, php load testing, laravel load testing, distributed load testing, load testing platform # VoltTest Cloud Closed Beta Is Now Open We're opening up access to **VoltTest Cloud** — the managed platform for running large-scale load tests without provisioning a single server. Until now, cloud mode has been limited to a small group of early testers. Starting today, anyone can join the waitlist, and we're approving access in waves. This post covers what VoltTest Cloud is, what you get in the closed beta, and exactly how the access process works from waitlist to your first cloud test run. TL;DR: VoltTest Cloud runs your PHP load tests on managed infrastructure — scale from hundreds to millions of concurrent users across regions without managing servers. The closed beta is now accepting waitlist signups. ![VoltTest Cloud Closed Beta Is Now Open](/img/volt-test-cloud-closed-beta-og.png) ## What Is VoltTest Cloud? If you've used the [VoltTest PHP SDK](https://github.com/volt-test/php-sdk), you know the workflow: define scenarios in plain PHP, run them on the high-performance Go engine, and read real percentile metrics. That works great from your own machine — up to a point. Generating serious load from a laptop or a single CI runner hits hard limits: open file descriptors, bandwidth, CPU. VoltTest Cloud removes that ceiling. Your test definition stays exactly the same — one line switches execution to managed infrastructure: ```php target('https://staging.example.com'); $test->cloud('vt_your_api_key'); // ← runs on VoltTest Cloud instead of locally $test->setVirtualUsers(500); $test->setDuration('5m'); ``` Using the [Laravel package](https://docs.volt-test.com/docs/laravel/laravel-quick-start)? It's just as simple — add your API key to `.env` and pass a flag: ```bash php artisan volttest:run CheckoutTest --cloud ``` Or enable it globally with `VOLTTEST_CLOUD_ENABLED=true` in your `config/volttest.php` — the [Cloud Execution docs](https://docs.volt-test.com/docs/laravel/laravel-cloud-mode) cover all the options. Either way, the test executes on dedicated cloud instances, and results — requests per second, P95/P99 latency, error breakdowns, time-series charts — land in your VoltTest dashboard, stored and comparable across runs. ![A completed test run in the VoltTest Cloud dashboard: 473,948 requests at 7,116 peak RPS, with automatic insights flagging P99 outlier spikes and a full latency distribution](/img/volt-test-cloud-run-overview.png) This run is a good example of why you load test in the first place: averages look healthy (35ms), but VoltTest's insights immediately flag that P99 is 126× higher than P50 — a tail-latency problem a quick manual check would never catch. ## What's Included in the Closed Beta Every beta account starts on the free plan: | | Free (Beta) | |---|---| | Max virtual users per test | **500** | | Max test duration | **10 minutes** | Everything else comes with the account: the full dashboard with metrics and run history, run comparison (up to 5 runs side-by-side), and the PHP SDK & Laravel integrations. 500 VUs for 10 minutes is enough to find real bottlenecks in most staging environments — connection pool exhaustion, N+1 queries under concurrency, and tail-latency spikes all show up well before that. We're finalizing paid tiers with higher limits during the beta — early users get a say in how they're shaped. Serious about scale?: If the free limits are holding you back, reach out at [hello@volt-test.com](mailto:hello@volt-test.com) — we're happy to upgrade serious beta testers to a higher package while pricing is being finalized. Tell us what you're testing and the load you need. ## How to Get Access We're keeping the beta *closed* — access is granted in waves — but the door is now open for everyone to request it. Here's the full journey: ### 1. Create Your Account Sign up at [volt-test.com/register](https://volt-test.com/register) — registering is how you join the waitlist. It's free, with no credit card and no commitment, and your account is already set up for the moment you're approved. Try VoltTest Cloud Free: ### 2. Verify Your Email Right after signing up, we'll send a 6-digit verification code to your inbox. Enter it and your account is active — you'll land on a *"You're on the waitlist"* screen while your access is being reviewed. ### 3. Get Approved We review the waitlist and approve access in waves. When it's your turn, you'll get an email — and if you're signed in, the waitlist screen notices your approval and takes you straight to the dashboard, no re-registering or refreshing needed. We're prioritizing teams actively load testing PHP and Laravel applications — if that's you, an email to [hello@volt-test.com](mailto:hello@volt-test.com) with a line about your use case helps us bump you up the queue. ### 4. Run Your First Cloud Test First, grab an API key: from the dashboard, open **Settings → API Keys**, click **Create API Key**, and give it a name (you can set an expiration, or leave it permanent). Copy the generated key — it starts with `vt_` and is shown only once, so store it somewhere safe. Then point your existing test at the cloud. With the PHP SDK: ```php $test->cloud('vt_your_api_key'); ``` With the Laravel package, add `VOLTTEST_API_KEY=vt_your_api_key` to `.env` and run: ```bash php artisan volttest:run YourTest --cloud ``` Run it the same way you always do — the SDK handles the rest, and your results appear in the dashboard in real time. The [Cloud Mode guide](https://docs.volt-test.com/docs/cloud-mode) (or [Cloud Execution for Laravel](https://docs.volt-test.com/docs/laravel/laravel-cloud-mode)) walks through the full setup. ## Why a Closed Beta? We'd rather grow deliberately than fall over publicly. A load testing platform has an unusual property: our users' job is to generate enormous amounts of traffic. Opening access in waves lets us watch capacity, harden the orchestration layer, and talk to every early user — your feedback directly shapes what we build next. If something breaks, confuses you, or is missing, we want to hear about it. Beta users get a direct line to us at [hello@volt-test.com](mailto:hello@volt-test.com). ## What's Next During the beta we're focused on: - **Paid tiers** — higher VU counts, longer tests, and parallel runs; pricing is being finalized now and will be announced during the beta - **Scheduled runs** — recurring cloud tests on a schedule, on top of the API-key-triggered runs you can already wire into CI today - **Regression detection** — automated baselines and pass/fail thresholds, building on the run comparison already in the dashboard ## Get Started Today 1. **Join the waitlist** — create your account at [volt-test.com/register](https://volt-test.com/register) 2. **Try it locally while you wait** — the [PHP SDK Getting Started guide](https://docs.volt-test.com/docs/getting-started) or the [Laravel Quick Start](https://docs.volt-test.com/docs/laravel/laravel-quick-start) takes about five minutes 3. **Read the cloud docs** — so you're ready to go the moment your invite lands: [Cloud Mode →](https://docs.volt-test.com/docs/cloud-mode) or [Cloud Execution for Laravel →](https://docs.volt-test.com/docs/laravel/laravel-cloud-mode) ## Learn More **On the platform** - [What VoltTest Cloud does →](/features) - [Load testing use cases →](/solutions) **Cloud documentation** - [Cloud Mode (PHP SDK) →](https://docs.volt-test.com/docs/cloud-mode) - [Cloud Examples →](https://docs.volt-test.com/docs/Examples/cloud-examples) - [Cloud Execution (Laravel Package) →](https://docs.volt-test.com/docs/laravel/laravel-cloud-mode) **PHP SDK** - [Installation →](https://docs.volt-test.com/docs/installation) - [Getting Started →](https://docs.volt-test.com/docs/getting-started) **Laravel package** - [Installation →](https://docs.volt-test.com/docs/laravel/laravel-installation) - [Quick Start →](https://docs.volt-test.com/docs/laravel/laravel-quick-start) - [Artisan Commands →](https://docs.volt-test.com/docs/laravel/laravel-cli-commands) **From the blog** - [How to Stress Test PHP and Laravel Applications →](/blog/php-stress-testing-tool) - [Performance Testing Types Explained →](/blog/performance-testing-types) --- ⭐ **Star the repository on GitHub:** [volt-test/php-sdk](https://github.com/volt-test/php-sdk) 💬 **Follow updates on X:** [@VoltTest](https://x.com/VT_Developers) --- --- ### PHP Stress Testing Tool: How to Stress Test PHP & Laravel Apps URL: https://volt-test.com/blog/php-stress-testing-tool Published: 2026-06-11 Keywords: php stress testing, how to stress test php, php stress test tool, php performance testing, php load testing tools, php performance testing tool, php stress test, php bottlenecks under load, php fpm max children, php session locking, load testing php # How to Stress Test PHP and Laravel Applications Choosing a **PHP stress test tool** usually means a painful trade-off: the popular load testing tools all live outside PHP, so you end up writing scenarios in JavaScript, Java, or XML instead of the language your app is built in. This guide takes a different approach. We'll cover what stress testing actually means for a PHP application, the bottlenecks that PHP apps specifically hit under load, what to look for in a tool, how the main options compare, and how to run your first stress test on plain PHP or Laravel in just a few minutes — without leaving your Composer workflow. TL;DR: Stress testing pushes your PHP application past its expected limits to find where it breaks. In PHP that's usually one of five things: FPM worker saturation, database connection limits or N+1 amplification, session locking, cache stampede, or a queue backlog. VoltTest lets you write the tests that find them in PHP itself, and run them locally or at cloud scale. ![PHP Stress Testing Tool](/img/php-stress-testing-tool-og.png) ## What Is Stress Testing in PHP? Stress testing pushes your application beyond its normal operating limits to find the point where it breaks — and to see *how* it breaks. It answers questions a single request never can: How many concurrent users can your API handle before response times spike? Does the database connection pool exhaust under load? Does the app fail gracefully or fall over? It's easy to confuse the different flavors of performance testing. The difference isn't the tool — it's the question you're asking: | | Load testing | Stress testing | Spike testing | |---|---|---|---| | **Question** | Does it hold up at expected traffic? | Where does it break, and how? | Does it survive a sudden surge? | | **Load profile** | Ramp to target, then hold | Keep climbing past target | Jump straight to a multiple of target | | **Pass condition** | P95 under budget, errors near zero | You found the limit and it degraded gracefully | It recovers once the surge passes | | **Typical trigger** | Pre-release regression check | Capacity planning before a campaign | Black Friday, a launch, a viral post | They overlap heavily and most tools (including VoltTest) handle all three. For a full breakdown of each type, see [Performance Testing Types](/blog/performance-testing-types). For the rest of this article we'll use "stress testing" loosely to mean putting your PHP app under realistic concurrent load. ### The Knee Matters More Than the Breaking Point Most teams stress test looking for the moment the application starts returning errors. That number is the *least* useful thing the test produces, because you will never run production anywhere near it. What you actually want is the **knee** — the virtual-user count where P95 latency stops rising gently and starts bending upward while throughput flattens. Below the knee, adding users adds throughput. Above it, adding users only adds queueing: the same requests per second, served more slowly to more people. The breaking point — 5xx responses, timeouts, connection resets — usually arrives well *after* the knee, and by then your users have been having a bad time for a while. So a useful PHP stress test produces three numbers, not one: - **The knee** — where latency starts bending. This is your real capacity. - **The breaking point** — where errors start. The gap between it and the knee is your headroom. - **Recovery time** — how long the system takes to return to baseline once load stops. An app that needs ten minutes to drain a queue has a very different failure mode from one that recovers in ten seconds. ## Common PHP Bottlenecks Under Stress Under load, a PHP application almost never fails where you expect. The code you spent an afternoon optimizing is rarely the constraint — the constraint is usually a *fixed-size resource* underneath it: a worker pool, a connection limit, a lock, a queue. Stress testing is how you find out which one you run out of first. These five account for most PHP failures under load. For each: what actually breaks, the signature it leaves in your metrics, and how to reproduce it deliberately. ### 1. PHP-FPM Worker Saturation PHP-FPM serves each request from a pool of worker processes capped by `pm.max_children`. When every worker is busy, new requests don't fail — they queue in the socket backlog. Then they wait. The arithmetic is unforgiving. With `pm.max_children = 20` and an average request taking 100ms, your ceiling is roughly 200 requests per second no matter how many virtual users you throw at it. This is the first wall most PHP apps hit, and it's routinely misdiagnosed as a slow database. **The signature:** throughput plateaus at a hard ceiling while latency climbs in a straight line. Double the virtual users and RPS doesn't move, but P95 roughly doubles. Push further and nginx starts returning `502 Bad Gateway` or `504 Gateway Timeout`. **Reproduce it** by ramping past the ceiling in stages and watching where the RPS line goes flat: ```php title="breakpoint-test.php" stage('1m', 50) // warm up ->stage('2m', 200) // climb ->stage('2m', 500) // past the expected ceiling ->stage('1m', 0); // ramp down and watch recovery $scenario = $voltTest->scenario('Product Listing'); $scenario->step('Browse products') ->get('https://staging.example.com/products') ->validateStatus('Products OK', 200); $voltTest->run(true); ``` **The fix is usually configuration, not code:** raise `pm.max_children` (bounded by available RAM ÷ average process size — over-provisioning here just moves the failure to swap), or shorten the time each worker is held. Shortening it generally means fixing one of the next four. ### 2. Database Connections and N+1 Amplification Two distinct database problems show up under stress, and they look different. The first is **connection exhaustion**. MySQL's `max_connections` and your FPM worker count are independent numbers that have to agree. Two hundred FPM workers each opening a connection against a `max_connections = 151` server produces `SQLSTATE[HY000] [1040] Too many connections` — an application-level 500, not a slow response. The second is **N+1 amplification**, and it's the more common one. A page that issues 30 queries at one virtual user issues 3,000 at a hundred. The query that took 2ms in isolation now waits behind ninety-nine copies of itself. Nothing in your single-request profiling predicts this, because the cost isn't in the query — it's in the contention. **The signature:** latency climbs with a *long tail*. P99 degrades far faster than P95 (a 5× gap between them is a strong hint), and the database host shows high CPU or lock waits while your PHP servers sit relatively idle. **Reproduce it** with realistic data variation, not one URL repeated. Hitting `/products/1` ten thousand times measures your query cache; hitting ten thousand different product IDs measures your database. VoltTest reads a CSV data source for this, in `sequential`, `random`, or `unique` mode, and interpolates the column into the request: ```php use VoltTest\DataSourceConfiguration; $scenario->setDataSourceConfiguration( new DataSourceConfiguration(__DIR__ . '/product_ids.csv', 'random', true) ); $scenario->step('Product detail') ->get('https://staging.example.com/products/${product_id}') ->validateStatus('Product OK', 200); ``` ### 3. Session Locking This is the PHP-specific bottleneck that surprises people most, because it doesn't exist in most other runtimes. PHP's default file-based session handler takes an **exclusive lock** on the session file for the duration of the request. Two concurrent requests carrying the same session cookie cannot run in parallel — the second one blocks until the first finishes and releases the lock. A modern page firing six AJAX requests at once executes them strictly one after another. **The signature:** latency scales with *requests per session*, not with virtual users. CPU sits idle on every tier while response times climb. The tell-tale comparison: the same steps run dramatically faster when the scenario doesn't carry cookies. That last point is also the reason most stress tests miss this entirely. If every virtual user is cookie-less and anonymous, there's no shared session and no lock to contend for — the test passes cleanly and production still stalls. Session persistence is opt-in: ```php $scenario = $voltTest->scenario('Authenticated Browsing') ->autoHandleCookies(); // without this, no session, no lock contention ``` **The fix:** move sessions to a non-locking handler (Redis with locking disabled), or call `session_write_close()` as soon as the request is done writing to the session — which releases the lock while the rest of the request runs. ### 4. Cache Misses and Stampede Your application is fast because the cache is warm. Stress testing a warm cache measures the cache, not the application. The dangerous moment is the **stampede**: a popular key expires, and every in-flight request misses simultaneously. All of them try to regenerate the same expensive value at once, and a query that normally runs once per five minutes runs five hundred times in one second. Under enough concurrency this alone can take down the database. **The signature:** steady-state numbers look excellent, but a spike profile — or the first sixty seconds after a deploy or `cache:clear` — shows a wall of latency followed by recovery. If your P95 is fine and your P99.9 is catastrophic, suspect regeneration. **Reproduce it** by flushing the cache immediately before a spike stage, so the surge lands on a cold cache the way a deploy does: ```php $voltTest->stage('10s', 500) // near-instant surge onto a cold cache ->stage('2m', 500) // hold, and watch whether it recovers ->stage('30s', 0); ``` **The fix:** single-flight regeneration (a lock so one request rebuilds while the others wait or serve stale), and staggered TTLs so keys written together don't expire together. ### 5. Queue Backlogs Queues are the bottleneck a stress test is most likely to declare healthy while the feature is broken. An endpoint that dispatches a job returns in 15ms whether the worker pool is idle or forty thousand jobs behind. Your HTTP metrics stay green — 100% success, low P95 — while order confirmations go out three hours late. The load test passed; the system failed. **The signature:** there isn't one in the HTTP metrics. That's the point. You have to watch queue depth and job latency *alongside* the run, and treat "backlog still draining ten minutes after the test ended" as a failure even when every request succeeded. On Laravel, that means watching Horizon (or `queue:monitor`) during the run and checking `failed_jobs` afterwards. Worker throughput is a fixed capacity like any other: if the endpoint can dispatch 500 jobs/second and your workers process 50, you have a 10× deficit that only shows up as a growing number somewhere else. ### Telling Them Apart When a stress test goes bad, the combination of symptoms usually narrows it to one suspect: | Symptom | Most likely cause | |---|---| | RPS flat, latency linear, PHP hosts at 100% CPU | FPM workers or CPU-bound code | | RPS flat, latency linear, everything *idle* | Session locking, or a blocking external call | | P99 far worse than P95, DB host busy | N+1 amplification or lock contention | | Fine in steady state, terrible for the first minute | Cold cache / stampede | | Every HTTP metric green, work not actually done | Queue backlog | | 500s with SQLSTATE 1040 | Connection limit mismatch with FPM workers | ## What to Look For in a PHP Stress Testing Tool Not every load testing tool fits a PHP team. Before picking one, check it against these criteria: - **PHP- and Composer-native** — can you write tests in PHP and install via Composer, or do you have to learn a separate language and toolchain? - **Realistic multi-step scenarios** — real users log in, browse, add to cart, and check out. The tool should chain requests and pass data (tokens, IDs, CSRF) between steps. - **Ramp-up and stages** — instantly hitting your app with 1,000 users isn't realistic. You want ramp-up, hold, spike, and ramp-down profiles. - **Percentile metrics** — averages hide problems. You need P95 and P99 latency, requests per second, and success/error rates. - **Session and cookie handling** — without it you only ever test anonymous traffic, and PHP's session lock (see above) never shows up. - **CI/CD integration** — stress tests are most valuable when they run automatically and catch regressions before they ship. - **Assertions** — the ability to fail a build when, say, P95 exceeds 150ms. - **Scale** — can it generate enough concurrent virtual users to actually stress your infrastructure? The first point is where most tools fall short for PHP developers — and where the comparison below gets interesting. ## PHP Stress Testing Tools Compared Here's an honest look at the most common options for stress testing a PHP application: | Tool | Write tests in | PHP-native | Laravel-native | Multi-step scenarios | Best for | |---|---|---|---|---|---| | **VoltTest** | PHP | Yes | Yes | Yes | PHP/Laravel teams who want native tests on a fast engine | | [k6](https://k6.io/) | JavaScript | No | No | Yes | JS-heavy teams comfortable scripting in JS | | [JMeter](https://jmeter.apache.org/) | XML / GUI | No | No | Yes | Protocol breadth and complex enterprise plans | | [Locust](https://locust.io/) | Python | No | No | Yes | Python teams | | [Apache Bench](https://httpd.apache.org/docs/current/programs/ab.html) (`ab`) | CLI flags | No | No | No | Quick one-off single-endpoint checks | There's no single "best" tool — it depends on your stack: - **k6** is excellent if your team already lives in JavaScript. ([VoltTest vs k6](/compare/volttest-vs-k6) covers where each one fits.) - **JMeter** is the veteran for protocol breadth and large enterprise test plans, at the cost of a heavier, GUI-driven workflow. ([VoltTest vs JMeter](/compare/volttest-vs-jmeter).) - **Apache Bench** is perfect for a quick `ab -n 1000 -c 50` sanity check on a single URL, but can't model real user journeys. - **VoltTest** is built specifically for PHP and Laravel developers: you write tests in PHP, install with Composer, and a Go engine handles the actual load generation — so you get PHP's ergonomics with Go's concurrency. It's the only option here with a [first-party Laravel package](/solutions/laravel-load-testing) — and on Laravel it gives you the same one-line speed as `ab` (`php artisan volttest:run `) *and* full multi-step scenarios when you need them. What it gives up for that focus: HTTP only (no JDBC, JMS or gRPC workloads), status-code-only per-step assertions, and the shortest track record of anything in this table. JMeter and k6 are the better tools when you need protocol breadth or richer assertions. The next sections show exactly how that works — from a stress test in plain PHP, to a full Laravel scenario, to a one-line CLI test you can fire off like `ab`. ## Stress Testing Plain PHP with VoltTest VoltTest's core SDK is framework-agnostic — it works with any PHP application, whether that's Symfony, WordPress, or raw PHP. Install it with Composer: ```bash composer require volt-test/php-sdk ``` Then define a scenario and run it. Here's a minimal stress test that hits your homepage: ```php title="stress-test.php" setVirtualUsers(50) ->setRampUp('10s') ->setDuration('1m'); // Define a scenario with one or more steps $scenario = $voltTest->scenario('Browse Homepage'); $scenario->step('Load homepage') ->get('https://your-app.test/') ->validateStatus('Homepage OK', 200); // Run the test — passing true streams the live report to your console $voltTest->run(true); ``` Run it like any PHP script: ```bash php stress-test.php ``` Because the heavy lifting happens in VoltTest's Go engine, a single machine can drive far more concurrent virtual users than a pure-PHP runner could — while you keep writing tests in the language you already use. That first script uses a *constant* load profile: a fixed number of virtual users, held for a fixed duration. It answers "does 50 users hurt?" — a load test question. To find the knee you need the load to keep climbing, which means stages: ```php title="find-the-knee.php" stage('30s', 25) // baseline: what does "healthy" look like? ->stage('1m', 100) ->stage('1m', 250) ->stage('1m', 500) ->stage('30s', 0); // ramp down — recovery is data too $scenario = $voltTest->scenario('Browse Homepage'); $scenario->step('Load homepage') ->get('https://staging.example.com/') ->validateStatus('Homepage OK', 200); $voltTest->run(true); ``` Start the ladder at a load you're confident is healthy. Without that baseline you get a breaking point with nothing to compare it against, and no way to tell whether P95 at 250 VUs is a problem or just Tuesday. ## Stress Testing a Laravel Application If you're on Laravel, the dedicated package builds on the core SDK and adds Laravel-specific conveniences: Artisan commands, automatic route discovery, and CSRF/cookie handling. Install it as a dev dependency: ```bash composer require volt-test/laravel-performance-testing --dev php artisan vendor:publish --tag=volttest-config ``` Scaffold a test with Artisan: ```bash php artisan volttest:make LoginTest ``` Then define the scenario. Note `extractCsrfToken()` — the package pulls Laravel's CSRF token out of the response automatically, so you don't have to: ```php title="app/VoltTests/LoginTest.php" target('http://localhost:8000'); $scenario = $manager->scenario('Login Flow'); $scenario->step('Get Login Page') ->get('/login') ->expectStatus(200) ->extractCsrfToken(); $scenario->step('Submit Login') ->post('/login', [ 'email' => 'user@example.com', 'password' => 'password', '_token' => '${csrf_token}', ]) ->expectStatus(302); } } ``` The Laravel package also supports **stages** (ramp-up, hold, spike, ramp-down), **CSV data sources** for driving tests with realistic data, and a **PHPUnit integration** so your stress tests run inside your existing test suite with assertions like `assertVTP95ResponseTime()`. Everything in the bottlenecks section above applies to Laravel too, with a few framework-specific wrinkles: Eloquent makes N+1 amplification easy to write by accident, the default `file` session driver carries the same lock as plain PHP, and queue backlogs are usually watched through Horizon. Three guides cover the Laravel workflow in depth: - [How to Load Test Laravel Applications](/blog/laravel-load-testing) — the full pillar guide: CSRF and Sanctum auth flows, queues, CI/CD, and interpreting Laravel-specific results. - [Stress Testing Laravel Applications with VoltTest (Web UI Flow)](/blog/stress-testing-laravel-with-volt-test-web-ui) — a full registration-to-dashboard scenario. - [Load Testing Laravel Applications with PHPUnit and VoltTest](/blog/laravel-load-testing-with-phpunit) — run performance assertions inside PHPUnit and catch regressions in CI. ## Quick One-Off Stress Tests from the Command Line Sometimes you don't want to write a test class at all — you just want to hammer one endpoint and see if it holds up, the way you would with `ab -n 1000 -c 50`. The Laravel package's `volttest:run` command does exactly that, with none of `ab`'s limitations. Stress test a single URL with 50 virtual users for one minute — the command auto-detects that the argument is a URL, so there's nothing else to configure: ```bash php artisan volttest:run https://api.example.com/health --users=50 --duration=1m ``` You can also stress test authenticated `POST` endpoints with a request body inline: ```bash php artisan volttest:run https://example.com/api/login \ --users=100 \ --method=POST \ --body='{"email":"test@example.com","password":"secret"}' ``` Useful flags (run `php artisan volttest:run --help` for the full list): | Flag | Purpose | |---|---| | `--users=` | Number of virtual users | | `--duration=` | How long to run (e.g. `30s`, `1m`, `5m`) | | `--method=` | HTTP method — `GET`, `POST`, `PUT`, `DELETE` | | `--body=` | Request body for `POST`/`PUT` | | `--headers=` | JSON string of request headers | | `--code-status=` | Expected HTTP status code (default `200`) | | `--stage=` | Load stages as `duration:target`, e.g. `--stage=1m:50 --stage=5m:100 --stage=1m:0` | | `--cloud` | Run the test on VoltTest Cloud | | `--stream` | Stream live output to the console | This gives you the one-liner speed of Apache Bench but with real virtual-user behavior, percentile metrics, ramp-up stages, and a path to cloud-scale execution — all from a single Artisan command. ## Reading Your Stress Test Results A stress test is only useful if you can interpret the report. VoltTest output looks like this: ```text Performance Report: Homepage Stress Test ---------------------------------------------------------------------- Total Requests: 5000 Success Rate: 99.94% Requests/Sec (RPS): 346.19 Avg Latency: 74.24ms P95 Latency: 128.71ms P99 Latency: 210.05ms ---------------------------------------------------------------------- ``` What to focus on: - **Success Rate** — anything below ~99% under load usually means the app is dropping requests or erroring out. - **Requests/Sec (RPS)** — your real-world throughput ceiling. - **Avg Latency** — useful, but it *hides* outliers. Don't ship on the average alone. - **P95 / P99 Latency** — the latency 95% and 99% of users experience. This is where real problems surface: an average of 74ms with a P99 of 2,000ms means 1 in 100 users is having a terrible time. ### The Saturation Signature A single run gives you a snapshot. Running the same scenario at increasing virtual-user counts and lining the numbers up gives you the shape — which is what you actually came for: | VUs | RPS | P95 | P99 | Errors | |---|---|---|---|---| | 50 | 340 | 129ms | 210ms | 0% | | 100 | 670 | 141ms | 233ms | 0% | | 200 | 690 | 402ms | 1,180ms | 0% | | 400 | 695 | 1,340ms | 4,900ms | 2.1% | Throughput stops growing between 100 and 200 virtual users. That's the knee, and this system's real capacity is around 100 concurrent users — not 400. Everything past the knee is queueing: the same ~690 requests per second delivered to twice as many people at three times the latency. The errors at 400 VUs are the breaking point, but the user-visible damage started 300 virtual users earlier, while the success rate still read 100%. Note also that P99 degrades much faster than P95 across those rows — the long-tail pattern from the database section above. On these numbers: The figures above are illustrative. The *shape* is what transfers between applications — a throughput plateau with climbing latency — not the specific values, which depend entirely on your hardware, your code, and your endpoint. ### Reading the Errors When requests do start failing, the status code narrows the search considerably: | What you see | Where to look first | |---|---| | `502 Bad Gateway` | PHP-FPM pool exhausted, or a worker died — check the FPM error log | | `504 Gateway Timeout` | A request outran nginx's `fastcgi_read_timeout` — usually a slow query or a blocking external API call | | `500` with `SQLSTATE` | Database connection limit, lock wait timeout, or a deadlock | | Connection reset / refused | You hit an OS or load-balancer limit before reaching PHP — `somaxconn`, file descriptors, ephemeral ports | | Timeouts reported only by the client | Frequently the load generator itself, not the target | That last row is worth taking seriously. A load generator saturating its own CPU reports latency that belongs to the test machine. Check the generator's resource usage before you go looking for the bottleneck in your application — VoltTest's Go engine keeps per-VU overhead low precisely so this happens later, but "later" is not "never". ## Common PHP Stress Testing Mistakes A few mistakes make stress test results misleading: - **Testing localhost** — your laptop is not production. Network, CPU, and database differ wildly. Test against a staging environment that mirrors production. - **No ramp-up** — slamming the app with all users at once measures a thundering herd, not real traffic. Use stages to ramp up gradually. - **Ignoring P99** — averages look fine while a slice of users suffer. Always read the tail latencies. - **Stress testing production unannounced** — you can take down a live system. Coordinate with your team, and prefer staging or a clearly-marked maintenance window. - **No baseline run** — a breaking point on its own is a number with nothing to compare it to. Establish the healthy P95 at low load first, then climb. - **Hammering one endpoint** — a single URL rarely exercises the resource you'll actually run out of. Real traffic mixes cheap and expensive routes and shares a session, and the interaction between them is where the bottleneck usually lives. - **Only ever testing a warm cache** — if you never test a cold start, you never test the scenario that follows every deploy. ## Run Large-Scale Stress Tests with VoltTest Cloud Running stress tests from one machine works well up to a point. To simulate hundreds of thousands of concurrent users from multiple regions, you need distributed infrastructure — and that's what VoltTest Cloud provides, without you managing a single server. Try VoltTest Cloud Free: Run distributed load tests at scale without managing infrastructure — 500 VUs free, no credit card. ## Conclusion Stress testing tells you how your PHP application behaves under pressure *before* your users find out the hard way. Most of the value isn't in the breaking point — it's in learning which of the five bottlenecks you hit first, because that's the one worth spending a sprint on. The right tool removes the friction: with VoltTest you write tests in PHP, install via Composer, run them against plain PHP or Laravel, and read real percentile metrics — all on a high-performance Go engine. Start with a baseline run on staging, add stages until throughput plateaus, note where the knee lands, and wire the test into CI so the next regression shows up in a pull request instead of in production. ## Learn More - [PHP Load Testing: How to Load Test PHP Applications →](/blog/php-load-testing) - [How to Load Test Laravel Applications →](/blog/laravel-load-testing) - [Performance Testing Types Explained →](/blog/performance-testing-types) - [Stress Testing Laravel with the VoltTest Web UI →](/blog/stress-testing-laravel-with-volt-test-web-ui) - [Load Testing Laravel with PHPUnit →](/blog/laravel-load-testing-with-phpunit) - [Load Testing PHP APIs →](/solutions/php-api-testing) - [Effortless Laravel Performance Testing with VoltTest PHP SDK →](/blog/effortless-laravel-performance-testing-with-volt-test-php-sdk) --- ⭐ **Star the repository on GitHub:** [volt-test/php-sdk](https://github.com/volt-test/php-sdk) 💬 **Follow updates on X:** [@VoltTest](https://x.com/VT_Developers) --- --- ### Load Testing Laravel Applications with PHPUnit and VoltTest URL: https://volt-test.com/blog/laravel-load-testing-with-phpunit Published: 2025-11-29 Keywords: laravel performance testing, laravel load testing, phpunit load test, volt-test, laravel testing tools # Introducing Load Testing Inside PHPUnit With VoltTest 1.2.0, you can now run load tests directly inside PHPUnit — no external scripts or configuration required. VoltTest was built to make load testing simple and native for PHP developers, and this new release takes it one step further. You can now test your Laravel APIs under load using the same PHPUnit environment you already use for your feature and unit tests. TL;DR: VoltTest 1.2.0 lets you run load tests directly inside PHPUnit — same test runner, same CI pipeline, with assertions for success rate, P95 latency, and error rate to catch performance regressions automatically. ![Load Testing Laravel Applications with PHPUnit and VoltTest](/img/laravel-phpunit-og.png) ## Why Does PHPUnit Integration Matter? Most Laravel developers already rely on PHPUnit for testing logic and features. Now, you can also measure your app’s behavior under load without leaving that familiar workflow. **This means:** - No switching to external tools or YAML scripts. - Run load tests in your CI/CD pipeline. - Catch performance regressions automatically. - Keep your load testing code version-controlled alongside your application tests. ## Installation If you already use the package, update it: ```bash composer update ``` or install fresh ```bash composer require volt-test/laravel-performance-testing ``` you can check the package configuration options and how you can use in the blog post [Effortless Laravel Performance Testing with VoltTest PHP SDK](/blog/effortless-laravel-performance-testing-with-volt-test-php-sdk). ## Configure PHPUnit In your `phpunit.xml` file, add a new testsuite for performance tests: ```xml .... tests/Performance ``` This tells PHPUnit to look for performance tests in the `tests/Performance` directory. Additionally, you can set environment variables for VoltTest in the `phpunit.xml` file: ```xml ``` Environment variables Explanation: - `VOLTTEST_BASE_PATH`: The base path for your Laravel application. (usually `.`) - `VOLTTEST_SERVER_PORT`: The Preferred port where your Laravel app will run during tests. - `VOLTTEST_ENABLE_SERVER_MANAGEMENT`: Enables automatic server management during tests without run you server (usually using this during you writing the test ). - `VOLTTEST_DEBUG_FOR_SERVER_MANAGEMENT`: Enables debug logs for server management (useful for troubleshooting). Alternatively, you can set these variables in your system environment or `.env` or `.env.testing` file. ```bash VOLTTEST_BASE_PATH=. VOLTTEST_SERVER_PORT=8009 VOLTTEST_ENABLE_SERVER_MANAGEMENT=true VOLTTEST_DEBUG_FOR_SERVER_MANAGEMENT=true ``` ## Writing Load Tests with PHPUnit and VoltTest Once installed and configure, you can create a new test file inside your Laravel app’s tests/Performance directory: ```php loadTestUrl('/', [ 'virtual_users' => 50, ]); // Assert that the success rate is above 99% $this->assertVTSuccessful($result, 99); // Assert that the 95th percentile response time is below 150ms $this->assertVTP95ResponseTime($result, 150); } } ``` In this example: - We create a `HomePageLoadTest` class that extends `PerformanceTestCase`. - We enable server management by setting the static property `$enableServerManagement` to `true`. So VoltTest will automatically start and stop your Laravel server during the test. - We define a test method `testHomePageUnderLoad` that runs a load test on the home page (`/`) with 50 virtual users. - We use assertions to verify that the success rate is above 99% and that the 95th percentile response time is below or equal 150 milliseconds. ## Running Your Load Tests To execute your load tests, run PHPUnit with the performance testsuite: ```bash vendor/bin/phpunit --testsuite Performance ``` This command will run all tests in the `tests/Performance` directory, including your load tests. You can also run a specific test file: ```bash vendor/bin/phpunit tests/Performance/HomePageLoadTest.php ``` ### Example Output PHPUnit interleaves VoltTest performance reports with your regular assertions—for example: ```text $ vendor/bin/phpunit --testsuite Performance PHPUnit 11.5.44 by Sebastian Bergmann and contributors. Runtime: PHP 8.4.15 Configuration: /path/to/app/phpunit.xml Performance Report: testHomePageUnderLoad Total Requests: 50 Success Rate: 100.00% Requests/Sec (RPS): 346.19 Avg Latency: 74.2426ms ---------------------------------------------------------------------- 1 / 1 (100%) Time: 00:01.524, Memory: 30.00 MB ``` if you have set up your CI/CD pipeline to run PHPUnit tests, your load tests will automatically be included in the test suite. if you need to run the test to you staging or production environment, you can set the `VOLTTEST_BASE_URL` environment variable before running PHPUnit: As normal phpunit if assertion of the load test failed the test will be marked as failed. so it can help you to catch performance regressions early in your development process. ## Advanced Load Testing Scenarios (Reusing Existing VoltTest Classes) If you've already created load tests using VoltTest's native syntax (covered in [Effortless Laravel Performance Testing with VoltTest PHP SDK](/blog/effortless-laravel-performance-testing-with-volt-test-php-sdk)), you can now reuse those classes inside your PHPUnit tests. Here is an example: ```php title="app/VoltTests/RegisterAndCheckoutTest.php" scenario('EcommerceAPITest') ->dataSource('registration_users.csv', 'sequential'); // Step 1 : Api.register $scenario->step('Api.register') ->post('/api/v1/register', [ 'name' => '${name}', 'email' => '${email}', 'password' => '${password}', 'password_confirmation' => '${password}', ], ['Content-Type' => 'application/json', 'Accept' => 'application/json']) ->extractJson('token', 'token.access_token') // Extract the token for subsequent requests ->expectStatus(201); // Step 2 : Api.products.index $scenario->step('Api.products.index') ->get('/api/v1/products', ['Authorization' => 'Bearer ${token}', 'Content-Type' => 'application/json', 'Accept' => 'application/json']) ->extractJson('id', 'data[0].id') // Extract the first product ID ->expectStatus(200); // Step 4 : Api.cart.add $scenario->step('Api.cart.add') ->post('/api/v1/cart/add', [ 'product_id' => '${id}', // Use the extracted product ID 'quantity' => 1, // Set a default quantity ], ['Authorization' => 'Bearer ${token}', 'Content-Type' => 'application/json', 'Accept' => 'application/json']) ->expectStatus(200); // Step 6 : Api.orders.checkout $scenario->step('Api.orders.checkout') ->post('/api/v1/orders/checkout', [ // No Body needed for checkout ], ['Authorization' => 'Bearer ${token}', 'Content-Type' => 'application/json', 'Accept' => 'application/json']) ->expectStatus(201); } } ``` This VoltTest class simulates user registration, product browsing, adding to cart, and checkout using a CSV data source for user details. You can then create a PHPUnit test that runs this VoltTest class under load to measure its performance and can also verify data integrity: ```php title="tests/Performance/RegisterAndCheckoutTest.php" create([ 'name' => 'Test Product', 'quantity' => 100, ]); $result = $this->runVoltTest(new EcomerceAPITest, [ 'virtual_users' => 10, ]); $this->assertVTSuccessful($result, 100); $this->assertVTErrorRate($result, 0); $this->assertVTMinResponseTime($result, 100); $this->assertVTAverageResponseTime($result, 200); $this->assertVTP95ResponseTime($result, 200); $this->assertVTP99ResponseTime($result, 200); // check the remain product in the inventory after test $this->assertEquals(90, Product::query()->first()->quantity, "Product quantity should be 90 after 10 registrations."); } } ``` When you run this PHPUnit test, it will execute the `RegisterAndCheckout` VoltTest class with 10 virtual users and report the performance metrics alongside your other PHPUnit tests. ```bash ./vendor/bin/phpunit --testsuite=Performance ``` ### Example Output The output will look like this: ```text ./vendor/bin/phpunit --testsuite=Performance PHPUnit 11.5.44 by Sebastian Bergmann and contributors. Runtime: PHP 8.4.15 Configuration: path/to/app/phpunit.xml ---------------------------------------------------------------------- Performance Report: testPerformanceFromExistingClass ---------------------------------------------------------------------- Total Requests: 40 Success Rate: 100.00% Requests/Sec (RPS): 162.91 Avg Latency: 52.854091ms P95 Latency: 72.748667ms P99 Latency: 78.206542ms ---------------------------------------------------------------------- . 1 / 1 (100%) Time: 00:00.787, Memory: 28.00 MB OK (1 test, 13 assertions) ``` In this PHPUnit test: - We create a `RegistrationPerformanceTest` class that extends `PerformanceTestCase`. - We define a test method `testPerformanceFromExistingClass` that runs the `RegistrationTest` VoltTest class with 10 virtual users. - We use various assertions to validate the performance metrics of the test. This approach allows you to leverage existing VoltTest classes while integrating them seamlessly into your PHPUnit test suite. This tests can catch **race conditions** and data integrity issues under load, ensuring your application behaves correctly even during high traffic scenarios. ## What Are the Benefits of PHPUnit Integration? By integrating VoltTest with PHPUnit, you gain several advantages: - **Unified Testing Workflow**: Manage all your tests—unit, feature, and performance—in one place. - **Automated Performance Regression Detection**: Catch performance issues early in your development cycle - **Reusable Test Logic**: Leverage existing VoltTest classes in your PHPUnit tests for consistency and code reuse. - **CI/CD Integration**: Seamlessly include load tests in your continuous integration pipelines. - **Comprehensive Reporting**: Get detailed performance metrics alongside your regular test results. ## What's Next for VoltTest? The PHPUnit integration is just one part of VoltTest's vision for simplifying performance testing. In the near future, we plan to introduce **VoltTest Cloud**—a hosted service that enables you to run large-scale load tests without managing infrastructure. Try VoltTest Cloud Free: Run distributed load tests at scale without managing infrastructure — 500 VUs free, no credit card. ## Conclusion Running load tests directly within PHPUnit using VoltTest simplifies performance testing for Laravel applications. It allows developers to maintain a consistent testing workflow, catch performance regressions early, and ensure their applications can handle real-world traffic. By leveraging existing VoltTest classes, you can also ensure data integrity under load, making your tests more robust and reliable. For the full picture of what the [Laravel load testing package](/solutions/laravel-load-testing) does — route scaffolding, session handling and CI gates — see the overview. ## Learn More - [GitHub Release Notes →](https://github.com/volt-test/laravel-performance-testing/releases/tag/1.2.0) - [Full PHPUnit Integration Docs →](https://github.com/volt-test/laravel-performance-testing/blob/main/docs/PHPUNIT_INTEGRATION.md) - [Previous Article: Effortless Laravel Load Testing with VoltTest PHP SDK →](/blog/effortless-laravel-performance-testing-with-volt-test-php-sdk) - [Stress Testing Laravel with the VoltTest Web UI →](/blog/stress-testing-laravel-with-volt-test-web-ui) --- ⭐ **Star the repository on GitHub:** [volt-test/laravel-performance-testing](https://github.com/volt-test/laravel-performance-testing) 💬 **Follow updates on X:** [@VoltTest](https://x.com/VT_Developers) --- --- ### Effortless Laravel Performance Testing with VoltTest PHP SDK URL: https://volt-test.com/blog/effortless-laravel-performance-testing-with-volt-test-php-sdk Published: 2025-08-09 Keywords: laravel performance testing, laravel load testing package, volt-test laravel sdk, php performance testing tool # Effortless Laravel Performance Testing — Without Leaving PHP When your Laravel app hits real traffic, will it *fly*… or will it *fall over*? Most load-testing tools make you jump through hoops — learn a new scripting language, spin up external services, or fight with configs that feel like they belong to another ecosystem. That’s why I built the **Laravel Performance Testing package**: a native, PHP-first way to run **load** and **stress tests** right inside your Laravel project — powered by the [VoltTest PHP SDK](https://docs.volt-test.com). You write your tests in plain PHP, keep them version-controlled with your codebase, and run them with a single [Artisan](https://laravel.com/docs/artisan) command. No context-switching. No external scripts. Just Laravel, PHP, and the performance insights you need before your users find the bottlenecks. TL;DR: The VoltTest Laravel package lets you write and run load tests inside your Laravel project with Artisan commands, route-based test generation, and CSV data sources — no external tools or languages needed. ![Effortless Laravel Performance Testing with VoltTest PHP SDK](/img/effortless-laravel-og.png) ## Why Was This Package Created? About a month ago, I released this package to make performance testing in Laravel: - **Easier** – no external scripts or frameworks to learn. - **Native** – tests live inside your Laravel project. - **Flexible** – from simple single-URL load tests to complex multi-step scenarios. --- ## What Features Does the Package Include? - **Laravel-friendly integration** – Works seamlessly with routes, middleware, and config. - **Artisan commands** – Generate and run tests directly from the CLI. - **Automatic route discovery** – Quickly build test scenarios from your existing routes. - **Variable extraction** – Reuse cookies, headers, JSON fields, and HTML values between steps. - **Data-driven testing** – Feed test data from CSV files for realistic simulations. - **Detailed metrics** – Success rate, RPS, average latency, P95 latency, and more. - **Report storage** – Save test results for later analysis. --- ## Installation Install via [Composer](https://getcomposer.org/): ```bash composer require volt-test/laravel-performance-testing ``` Publish the configuration file: ```bash php artisan vendor:publish --tag=volttest-config ``` This creates `config/volttest.php` where you can tweak settings like default virtual users, duration, and report paths. --- ## Quick Start You can run a quick performance test without writing any code: ```bash php artisan volttest:run https://example.com/api/login --users=100 --method=POST --body='{"email":"test@example.com","password":"secret"}' ``` Or, you can create a reusable test class: ```bash php artisan volttest:make ExampleTest ``` This generates `app/VoltTests/ExampleTest.php`: ```php namespace App\VoltTests; use VoltTest\Laravel\Contracts\VoltTestCase; use VoltTest\Laravel\VoltTestManager; class ExampleTest implements VoltTestCase { public function define(VoltTestManager $manager): void { $manager->scenario('ExampleTest') ->step('Visit Home Page') ->get('https://example.com') ->validateStatus('success', 200); } } ``` Run it with: ```bash php artisan volttest:run ExampleTest --users=50 --duration=30 ``` --- ## Route-Based Test Generation Skip manual coding by letting the package generate tests from your Laravel routes. ```bash # Include all routes php artisan volttest:make ApiTest --routes # Filter by pattern php artisan volttest:make ApiTest --routes --filter="api/*" # Only GET routes php artisan volttest:make ApiTest --routes --method=GET # Only authenticated routes php artisan volttest:make ApiTest --routes --auth # Interactive selection php artisan volttest:make ApiTest --routes --select ``` --- ## Data-Driven Testing Simulate realistic usage with CSV files: **users.csv** ```csv name,email,password John Doe,user1@example.com,password123 Jane Smith,user2@example.com,password456 ``` **Test definition:** ```php $manager->scenario('RegisterTest') ->dataSource('users.csv') ->step('Register User') ->post('/register', [ 'name' => '${name}', 'email' => '${email}', 'password' => '${password}', ]); ``` --- ## Extract and Reuse Values You can capture values from responses and reuse them in later steps. **CSRF token from HTML** ```php $scenario->step('Get Login Page') ->get('/login') ->extractCsrfToken('csrf_token'); $scenario->step('Submit Login') ->post('/login', [ '_token' => '${csrf_token}', 'email' => 'user@example.com', 'password' => 'secret', ]); ``` **JSON field** ```php $scenario->step('Get User') ->get('/api/user') ->extractJson('user_id', 'data.id'); ``` **Header** ```php $scenario->step('Get Token') ->get('/auth') ->extractHeader('Authorization', 'Bearer ${token}'); ``` --- ## Analyzing Results After running a test, you’ll see metrics such as: - Success rate - Requests per second (RPS) - Average & P95 latency - Duration - Errors If `save_reports` is enabled, you’ll find detailed reports in: ``` storage/volttest/reports ``` --- ## Conclusion With **Laravel Performance Testing** powered by the **VoltTest PHP SDK**, you can: - Keep performance tests right inside your Laravel project. - Run them with one simple Artisan command. - Get detailed, actionable performance metrics before your users ever notice a slowdown. No separate scripting language. No complex setup. Just **Laravel, PHP, and the truth about your app’s performance**. For a comprehensive comparison of PHP load testing tools and when to use each, see our [PHP Load Testing guide](/blog/php-load-testing). A full walkthrough of the [Laravel package and its Artisan commands](/solutions/laravel-load-testing) is also available. If you need to push past expected traffic to find breaking points, check out the [PHP Stress Testing Tool guide](/blog/php-stress-testing-tool). **Docs:** [Laravel Performance Testing on GitHub](https://github.com/volt-test/laravel-performance-testing) **VoltTest PHP SDK:** [docs.volt-test.com](https://docs.volt-test.com) Pro Tip: Integrate VoltTest into your CI pipeline to catch performance regressions before they hit production. See [Load Testing Laravel with PHPUnit](/blog/laravel-load-testing-with-phpunit) for a step-by-step guide. Try VoltTest Cloud Free: Run distributed load tests at scale without managing infrastructure — 500 VUs free, no credit card. --- ### Performance Testing: Types and Differences with Examples URL: https://volt-test.com/blog/performance-testing-types Published: 2025-03-03 Keywords: performance testing types, load testing vs stress testing, spike testing, soak testing # Performance Testing: Types and Differences with Examples Performance testing is an essential process in software development that evaluates a system's responsiveness, stability, and scalability under different conditions. It helps identify bottlenecks and ensures applications meet performance expectations before deployment. There are several types of performance testing, each serving a different purpose. By understanding these types, you can choose the right tests to conduct based on your application's requirements. In this article, we will explore these types, their differences, and provide practical examples. TL;DR: Performance testing comes in seven main types — load, stress, spike, endurance, scalability, volume, and latency — each answering a different question about your application's behavior under pressure. ## What Is Load Testing? ### Definition Load testing measures a system's behavior under `expected` user loads. It ensures that the system can handle a specified number of users or transactions simultaneously without degradation in performance. For a hands-on guide to running load tests on PHP applications, see [PHP Load Testing: How to Load Test PHP Applications](/blog/php-load-testing). ### Example A SaaS-based school management system is expected to support 10,000 concurrent students during exam submission. A load test simulates these 10,000 users submitting their answers within a short period to evaluate how the system handles the load. So Here You know the expected load, you are testing the system under that load. ## What Is Stress Testing? ### Definition Stress testing evaluates a system's behavior under extreme conditions, often `beyond its normal operational capacity`. It helps determine the breaking point and whether the system fails gracefully. For a practical stress testing walkthrough, see [PHP Stress Testing Tool: How to Stress Test PHP & Laravel Apps](/blog/php-stress-testing-tool). ### Example A cloud-based e-commerce platform is expected to handle 100,000 users during peak shopping hours. A stress test increases the load gradually to 200,000 users to observe if the system crashes or recovers after failure. ## What Is Spike Testing? ### Definition Spike testing analyzes how a system handles sudden and extreme increases in load. It helps identify whether the system scales effectively or crashes under sudden traffic spikes. ### Example A ticket booking system for a concert sees an abrupt spike in traffic when tickets go on sale. A spike test simulates a rapid increase from 1,000 to 50,000 users within a minute to test system stability. ## What Is Endurance Testing? ### Definition Endurance testing evaluates a system's performance over an extended period under normal expected loads. It detects memory leaks, slowdowns, and other long-term performance issues. ### Example A banking application undergoes endurance testing by simulating `5,000 users performing transactions continuously over 24 hours` to ensure `there are no memory leaks` or `performance degradation`. ## What Is Scalability Testing? ### Definition Scalability testing assesses a system's ability to handle increased loads by adding resources. It helps determine how the system scales vertically or horizontally to accommodate more users or transactions. ### Example A cloud-based video streaming platform scales horizontally by adding more servers to handle increased user traffic during peak hours. Or it scales vertically by upgrading server resources to improve performance. then downgrades the resources when the traffic decreases. ## What Is Volume Testing? ### Definition Volume testing measures how the system performs with a large volume of data. It helps identify database performance issues, indexing problems, and storage limitations. ### Example A CRM system undergoes volume testing by loading `1 million customer records` to evaluate how the system handles the data volume. It checks if the system slows down, crashes, or maintains performance with the large dataset. ## What Is Latency Testing? ### Definition Latency testing evaluates a system's response time under different network conditions. It helps identify delays in data transmission, network congestion, and server processing times. ### Example A real-time multiplayer game undergoes latency testing to measure the time it takes for player actions to reflect on other players' screens. It simulates high latency, packet loss, and network congestion to observe how the game performs under these conditions. ## What Are the Differences Between Performance Testing Types? | Type | Tests For | Load Level | Duration | Key Question | |------|-----------|-----------|----------|--------------| | Load | Expected traffic | Normal | Minutes–hours | Can we handle Tuesday at 2 pm? | | Stress | Breaking point | Beyond limits | Minutes | Where does it break? | | Spike | Sudden surges | Sudden extreme | Seconds–minutes | Does it survive a flash crowd? | | Endurance | Long-term stability | Normal, sustained | Hours–days | Do memory leaks appear over time? | | Scalability | Resource scaling | Incrementally increasing | Variable | Does adding servers help? | | Volume | Data volume | Normal | Variable | Does performance degrade with 1 M rows? | | Latency | Response delays | Variable | Variable | How fast does the user see a response? | - **Load Testing vs. Stress Testing**: Load testing evaluates a system under expected loads, while stress testing pushes the system beyond its limits. - **Spike Testing vs. Endurance Testing**: Spike testing simulates sudden load spikes, while endurance testing evaluates long-term performance. - **Scalability Testing vs. Volume Testing**: Scalability testing assesses the system's ability to scale, while volume testing measures performance with large data volumes. - **Latency Testing**: Latency testing evaluates response times under different network conditions. These categories align with the [ISTQB performance testing taxonomy](https://www.istqb.org/), the industry-standard classification for software testing disciplines. ## Conclusion Performance testing is crucial for ensuring software applications meet performance expectations and deliver a seamless user experience. By understanding the different types of performance testing and their purposes, you can identify the right tests to conduct based on your application's requirements. Whether you need to evaluate expected loads, extreme conditions, scalability, or latency, performance testing helps you optimize your system for peak performance. Ready to put this into practice? Start with our [PHP load testing guide](/blog/php-load-testing) or learn how to [stress test Laravel applications step by step](/blog/stress-testing-laravel-with-volt-test-web-ui). For background on how VoltTest approaches performance testing with a PHP-native interface, see [Introducing VoltTest](/blog/introducing-volt-test-php-load-testing), or browse the [use-case guides for PHP APIs, Laravel apps and e-commerce flows](/solutions). --- ### Stress Testing Laravel Applications with VoltTest (Web UI Flow) URL: https://volt-test.com/blog/stress-testing-laravel-with-volt-test-web-ui Published: 2025-02-28 Keywords: stress testing laravel, laravel load testing, laravel performance testing, volt-test laravel # Introduction In this tutorial, we will explore how to perform stress testing on a Laravel application using the VoltTest PHP SDK. You will learn how to: * Simulate multiple users interacting with your Laravel application. * Test user registration and authentication workflows. * Measure application performance under load. * Extract dynamic values like CSRF tokens during test execution. * Use a CSV file as a data source for testing. * Analyze and optimize performance bottlenecks. By the end of this guide, you will be able to confidently run automated performance tests to ensure your Laravel app is scalable and resilient. TL;DR: This tutorial shows how to stress test a Laravel web application with VoltTest — simulating user registration, CSRF token extraction, and dashboard access under concurrent load using CSV-driven test data. ![Stress test Laravel web UI flows with VoltTest: multi-step user journeys with CSRF and sessions handled](/img/stress-testing-laravel-og.png) ## Prerequisites Ensure you have the following: - A running Laravel application - PHP 8.0 or higher - Composer installed ## Installing VoltTest PHP SDK First, install the VoltTest PHP SDK via Composer in your Laravel project: ```bash title="Terminal" composer require volt-test/php-sdk ``` Or clone the repository: ```bash title="Terminal" git clone https://github.com/volt-test/php-sdk.git cd php-sdk composer install ``` **For _Windows_ users,** Visit the installation guide [here](https://docs.volt-test.com/docs/installation#running-on-windows) ## Creating Test Data For a realistic test, create a CSV file (`users.csv`) with test user data: ```csv title="users.csv" email,password user1@example.com,password123 user2@example.com,password123 user3@example.com,password123 user4@example.com,password123 user5@example.com,password123 ``` Place this file in your project directory. ## Writing the Stress Test Create a file named `laravel_stress_test.php` in your project root and add the following script (or you can use the laravel's command): ```php title="laravel_stress_test.php" setVirtualUsers(5) ->setDuration('60s') // Optional: Set test duration ->setRampUp('10s') // Optional: Set ramp-up time ->setHttpDebug(true); // Enable HTTP debug logging for checking requests before sending the all requests // Create test scenario $userFlowScenario = $test->scenario('User Registration Flow') ->autoHandleCookies(); // Automatically handle cookies without extract them // Set up data source $userFlowScenario->setDataSourceConfiguration( new DataSourceConfiguration(__Dir__ . '/users.csv', 'unique', true) // Load data from CSV file, should be the full path ); // Step 1: Visit home page $userFlowScenario->step('Visit Home Page') ->get('http://localhost:8000') ->header('Accept', 'text/html') ->validateStatus('home_page_loaded', 200) ->setThinkTime('2s'); // Step 2: Visit register page and extract CSRF token $userFlowScenario->step('Visit Register Page') ->get('http://localhost:8000/register') ->header('Accept', 'text/html') ->extractFromHtml('csrf_token', 'input[name="_token"]', 'value') ->validateStatus('register_page_loaded', 200) ->setThinkTime('2s'); // Step 3: Submit registration form $userFlowScenario->step('Submit Registration') ->post( 'http://localhost:8000/register', '_token=${csrf_token}&name=Test User&email=${email}&password=${password}&password_confirmation=${password}' ) ->header('Content-Type', 'application/x-www-form-urlencoded') ->validateStatus('registration_successful', 302) ->setThinkTime('1s'); // Step 4: Access dashboard $userFlowScenario->step('Visit Dashboard') ->get('http://localhost:8000/dashboard') ->header('Accept', 'text/html') ->validateStatus('dashboard_loaded', 200) ->setThinkTime('3s'); // Run test $result = $test->run(true); // true enables real-time progress output // Display results summary in case you turned off the real-time progress output echo "\n\nTest Results Summary:\n"; echo "====================\n"; echo "Total Requests: " . $result->getTotalRequests() . "\n"; echo "Success Rate: " . $result->getSuccessRate() . "%\n"; echo "Requests/second: " . $result->getRequestsPerSecond() . "\n"; echo "Min Response Time: " . $result->getMinResponseTime() . "\n"; echo "Max Response Time: " . $result->getMaxResponseTime() . "\n"; echo "Avg Response Time: " . $result->getAvgResponseTime() . "\n"; echo "P95 Response Time: " . $result->getP95ResponseTime() . "\n"; ``` ### Code Explanation The stress test script simulates multiple users interacting with a Laravel web application. Here’s how it works: 1. **Initialize VoltTest**: ```php title="laravel_stress_test.php" $test = new VoltTest( 'Laravel User Flow', 'Tests home page visit, user registration, and dashboard access' ); ``` - Creates a new test instance with a descriptive name. 2. **Configure test parameters**: ```php title="laravel_stress_test.php" $test ->setVirtualUsers(5) ->setDuration('60s') ->setRampUp('10s') ->setHttpDebug(true); ``` - **5 virtual users**: Simulate 5 concurrent users. - **Running the test for 60 seconds**: Optional - you can remove this line to run the test and finish when all virtual users finish their scenarios. - **Ramping up over 10 seconds**: Optional - you can remove this line to start all virtual users at the same time. - **Enables HTTP debug logging**: Optional - Inspect requests while sending them. 3. **Create a test scenario**: ```php title="laravel_stress_test.php" $userFlowScenario = $test->scenario('User Registration Flow') ->autoHandleCookies(); ``` - Creates a scenario for user registration flow. - **autoHandleCookies()**: Automatically handles cookies without extracting them. 4. **Set up data source**: ```php title="laravel_stress_test.php" $userFlowScenario->setDataSourceConfiguration( new DataSourceConfiguration(__Dir__ . '/users.csv', 'unique', true) ); ``` - Loads user data from `users.csv` file. To simulate different users for each virtual user. 5. **Define test steps**: ```php title="laravel_stress_test.php" $userFlowScenario->step('Visit Home Page') ->get('http://localhost:8000') ->header('Accept', 'text/html') ->validateStatus('home_page_loaded', 200) ->setThinkTime('2s'); ``` - **Visit Home Page**: Sends a GET request to the home page. - **Accept header**: Optional - Specifies the expected response content type. - **Validate Status**: Optional - Checks if the response status is 200. - **Think Time**: Optional - Simulates user thinking time before the next step, so the virtual user will wait 2s before execute the next request. 6. **Extract CSRF token from registration page**: ```php title="laravel_stress_test.php" $userFlowScenario->step('Visit Register Page') ->get('http://localhost:8000/register') ->header('Accept', 'text/html') ->extractFromHtml('csrf_token', 'input[name="_token"]', 'value') ->validateStatus('register_page_loaded', 200) ->setThinkTime('2s'); ``` - Visits the registration page. - Extracts the [CSRF token](https://laravel.com/docs/csrf) from the HTML response. The token is stored in the variable `${csrf_token}`. - The way to extract the token is by using the `extractFromHtml` method, which takes the token name, the selector, and the attribute name. 7. **Submit registration form**: ```php title="laravel_stress_test.php" $userFlowScenario->step('Submit Registration') ->post( 'http://localhost:8000/register', '_token=${csrf_token}&name=Test User&email=${email}&password=${password}&password_confirmation=${password}' ) ->header('Content-Type', 'application/x-www-form-urlencoded') ->validateStatus('registration_successful', 302) ->setThinkTime('1s'); ``` - Submits the registration form with the extracted CSRF token and user data. - Validates the response status code. - Sets a 1-second think time before the next step. - The `${email}` and `${password}` variables are replaced with values from the CSV file. - The `${csrf_token}` variable is replaced with the extracted CSRF token. - The `validateStatus` method checks if the response status is 302 (redirect). - The `setThinkTime` method simulates user thinking time before the next step. 8. **Access dashboard**: ```php title="laravel_stress_test.php" $userFlowScenario->step('Visit Dashboard') ->get('http://localhost:8000/dashboard') ->header('Accept', 'text/html') ->validateStatus('dashboard_loaded', 200) ->setThinkTime('3s'); ``` Ensures successful login by verifying dashboard access. 9. **Run the test**: ```php title="laravel_stress_test.php" $result = $test->run(true); ``` - Executes the test with real-time progress output. ## Running the Test Execute the script: ```bash php laravel_stress_test.php ``` You'll see real-time progress, followed by a summary of test results. ## Analyzing Results ### Key Metrics: - **Success Rate**: Should be as close to 100% as possible - **Response Times**: Lower is better - **Requests per Second**: Higher means better scalability ## What Are Common Stress Testing Issues and How Do You Fix Them? ### Low Success Rate - **Possible Cause**: Server overload - **Solution**: Reduce virtual users or optimize queries ### High Response Times - **Possible Cause**: Database bottlenecks - **Solution**: Optimize queries, enable caching ### CSRF Token Extraction Fails - **Possible Cause**: HTML structure changes - **Solution**: Update the selector ## Next Steps - Expand tests to cover more user flows - Test with more virtual users — see our [PHP stress testing tool guide](/blog/php-stress-testing-tool) for scaling strategies - [Automate load tests in your PHPUnit CI pipeline](/blog/laravel-load-testing-with-phpunit) - Scaffold tests straight from your route table with the [Laravel package](/solutions/laravel-load-testing) ## Conclusion Using VoltTest for stress testing helps identify Laravel application bottlenecks before they impact users. Regular testing ensures scalability and reliability. For a deeper dive into the different types of performance testing (load, stress, spike, endurance), see our [performance testing types guide](/blog/performance-testing-types). Or jump straight to our comprehensive [PHP load testing guide](/blog/php-load-testing) for the full picture. Happy testing! ## Get in Touch For questions, discussions, or contributions, feel free to open an issue or start a discussion on the VoltTest GitHub repository: [https://github.com/volt-test/php-sdk](https://github.com/volt-test/php-sdk) Try VoltTest Cloud Free: Run distributed load tests at scale without managing infrastructure — 500 VUs free, no credit card. --- ### Introducing VoltTest: Stress & Load Testing for PHP Developers URL: https://volt-test.com/blog/introducing-volt-test-php-load-testing Published: 2025-02-26 Keywords: volt-test php sdk, php load testing, php performance testing, php stress testing tool # Introducing VoltTest PHP SDK: Seamless Performance Testing for PHP Applications Performance testing is crucial in modern application development, yet many developers skip it due to complex tools that don’t fit into PHP workflows. Today, I’m excited to introduce **VoltTest PHP SDK**, a powerful load testing tool with a PHP-native interface backed by Go’s exceptional performance capabilities. TL;DR: VoltTest is a PHP-native load testing SDK powered by a Go engine. Write tests in PHP, install via Composer, and simulate concurrent users without learning a new language or spinning up external tools. ## What Problem Does VoltTest Solve? As a PHP developer, I’ve often faced a common challenge: existing performance testing tools often require learning a new language, platform, or configuration syntax. This cognitive overhead leads many teams to defer proper load testing or rely on third-party services, creating additional costs and dependencies. VoltTest bridges this gap by providing: - A **fluent, intuitive PHP API** that feels natural to PHP developers - The **raw power of Go** for generating heavy loads with minimal resources - **No additional infrastructure** requirements beyond your existing PHP environment - **Comprehensive metrics** to identify bottlenecks and performance issues ## How Does VoltTest Work? VoltTest employs a unique dual-language architecture that delivers the best of both worlds: 1. Your **PHP code** defines test scenarios, configurations, and validation rules 2. The **SDK** transforms these definitions into a format the Go engine understands 3. The **Go engine** executes the actual load testing with true concurrency 4. **Results** are streamed back to your PHP application for analysis This architecture allows you to write and maintain tests in familiar PHP syntax while benefiting from Go's exceptional performance characteristics for the load generation. ## What Are VoltTest's Key Features? - **Fluent API**: Natural, chainable PHP methods for defining test scenarios - **Multi-scenario support**: Test different user flows with configurable weight distribution - **Variable extraction**: Capture and reuse values from responses (cookies, headers, JSON paths and HTML) - **Data-driven testing**: Feed tests with CSV files to simulate realistic user data - **Detailed metrics**: Get comprehensive performance insights including response times, throughput, and error rates ## Getting Started with VoltTest Let's create a simple performance test to demonstrate VoltTest's capabilities: ```php setVirtualUsers(50) // Number of concurrent users ->setDuration('30s') // Test duration ->setRampUp('5s') // Gradually ramp up to full load ->setHttpDebug(false); // Disable HTTP debug output // Create a test scenario $apiScenario = $test->scenario('API Flow') ->setWeight(100); // Full weight (100%) to this scenario // Define the first step - Get auth token $apiScenario->step('Get Token') ->post('https://api.example.com/auth', '{"username":"test","password":"test123"}') ->header('Content-Type', 'application/json') ->extractFromJson('token', 'data.token') // Extract token from response ->validateStatus('success', 200); // Define the second step - Use the token $apiScenario->step('Get User Data') ->get('https://api.example.com/users/me') ->header('Authorization', 'Bearer ${token}') // Use extracted token ->validateStatus('success', 200); // Run the test $result = $test->run(true); // true enables real-time progress output // Display results echo "Success Rate: " . $result->getSuccessRate() . "%\n"; echo "Requests/sec: " . $result->getRequestsPerSecond() . "\n"; echo "Avg Response: " . $result->getAvgResponseTime() . "\n"; echo "P95 Response: " . $result->getP95ResponseTime() . "\n"; ``` ## Advanced Features: Testing with Real-World Data VoltTest supports data-driven testing with CSV files, allowing you to simulate diverse user behaviors: ```php // users.csv contains columns: email,password,user_id $loginScenario->setDataSourceConfiguration( new DataSourceConfiguration('users.csv', 'random', true) ); // Now you can reference CSV columns in your requests $loginScenario->step('Login') ->post('https://example.com/login', 'email=${email}&password=${password}') // Variables from CSV ->validateStatus('success', 200); ``` ## Extracting and Using Dynamic Values One of VoltTest's most powerful features is its ability to extract and reuse values from responses: ```php // Extract CSRF token from HTML response $scenario->step('Get Login Page') ->get('https://example.com/login') ->extractFromHtml('csrf_token', 'input[name="_token"]', 'value') ->validateStatus('success', 200); // Use the extracted token in the next request $scenario->step('Submit Login') ->post('https://example.com/login', '_token=${csrf_token}&email=user@example.com&password=secret') ->validateStatus('success', 302); // Expecting a redirect ``` ## Understanding Your Results VoltTest provides comprehensive metrics to analyze performance: ```php $result = $test->run(); // Access detailed metrics echo "Test duration: " . $result->getDuration() . "\n"; echo "Total requests: " . $result->getTotalRequests() . "\n"; echo "Success rate: " . $result->getSuccessRate() . "%\n"; echo "Requests/second: " . $result->getRequestsPerSecond() . "\n"; echo "Min response time: " . $result->getMinResponseTime() . "\n"; echo "Max response time: " . $result->getMaxResponseTime() . "\n"; echo "Avg response time: " . $result->getAvgResponseTime() . "\n"; echo "Median response time: " . $result->getMedianResponseTime() . "\n"; echo "P95 response time: " . $result->getP95ResponseTime() . "\n"; echo "P99 response time: " . $result->getP99ResponseTime() . "\n"; ``` ## Why Was VoltTest Created? As PHP developers, I’ve often found performance testing to be a challenge. Existing tools like [JMeter](https://jmeter.apache.org/), [Gatling](https://gatling.io/) or [Locust](https://locust.io/) are powerful but require learning new syntax, languages or complex GUIs. We wanted a tool that would: 1. **Feel native to PHP developers** with an intuitive, fluent API 2. **Handle serious load testing** without requiring huge resources 3. **Integrate seamlessly** with PHP codebases and workflows 4. **Provide comprehensive metrics** with minimal configuration VoltTest achieves this through a unique architecture that lets you write your tests in familiar PHP syntax while leveraging Go's exceptional performance capabilities for the actual load generation. ## What Makes VoltTest Different? Unlike traditional PHP-based testing tools that struggle with concurrency limitations, VoltTest uses a high-performance Go engine that runs behind the scenes. This gives you: - **True concurrent users** instead of PHP's process-based concurrency - **Minimal resource usage** even when simulating thousands of users - **Accurate timing and metrics** collection for detailed analysis VoltTest brings modern stress testing to PHP with an intuitive API and high-performance Go engine. No new languages, no complex setup—just performance insights when you need them. ## Conclusion VoltTest PHP SDK brings enterprise-grade performance testing capabilities to PHP developers with a familiar, easy-to-use API. By combining PHP’s developer-friendly syntax with Go’s raw performance power, VoltTest enables teams to integrate load testing directly into their development workflows without additional infrastructure or expertise. Whether you’re building APIs, websites, or complex applications, VoltTest gives you the tools to ensure your PHP applications can handle real-world traffic with confidence. ## Getting Started 💡 Ready to test your PHP app’s performance? Try VoltTest today! 🚀 ```bash composer require volt-test/php-sdk ``` For more examples and detailed documentation, visit [Examples Page in docs](https://docs.volt-test.com/docs/category/examples). ## Keep Reading - [PHP Load Testing: The Complete Guide →](/blog/php-load-testing) - [Stress Testing Laravel Applications (Web UI Flow) →](/blog/stress-testing-laravel-with-volt-test-web-ui) - [Load Testing Laravel with PHPUnit →](/blog/laravel-load-testing-with-phpunit) - [What the VoltTest platform does →](/features) - [How VoltTest compares to other load testing tools →](/compare)