Pest 5 TIA Tested: 0 to 200 Reruns, Depending on the Edit
By Nihar Ranjan Das · Sat Oct 10 2026 · 11 min read · 0 views
View as a Web StorySoftware#testing#ci#Pest#Laravel#tia

Pest 5 test impact analysis reran anywhere from 0 to all 200 tests in my Laravel 13 app, depending entirely on which file I touched. A comment change reran nothing; a change to phpunit.xml reran everything and took longer than a plain run.
If you are deciding whether to upgrade, the short version is this. Pest 5 needs PHP 8.4 and PHPUnit 13. Its Laravel plugin needs Laravel 13.23 or newer, so a Laravel 12 project should stay on Pest 4. TIA also needs git and a coverage driver, and without the driver it quietly does nothing.
What does Pest 5 test impact analysis do?
Test impact analysis, or TIA, is a Pest 5 feature that records which source files each test touches, then reruns only the tests affected by your changes and replays cached results for the rest. You switch it on with the --tia flag. Pest is a PHP testing framework built on PHPUnit, and PHPUnit is the test runner underneath it, so a Pest major version always tracks a PHPUnit major version.
Pest 5 is the first major release of Pest built on PHPUnit 13. According to the Laravel News write-up of Pest 5, Taylor Otwell said the feature took Laravel Cloud's own suite of more than 19,000 tests from 3 minutes to 5 seconds. That is a vendor number for a very large suite. I wanted to know what happens on a normal-sized app where the edit is not always the friendly kind.
What was the test setup?
The test setup was a fresh composer create-project laravel/laravel app, Laravel 13.35.0 on PHP 8.4.7, with Pest 5.3.1 and PHPUnit 13.4.1. I wrote 200 tests. Thirty unit test files check small service classes, five tests each, which is 150 tests. Ten feature test files exercise a tiny articles controller through HTTP and use RefreshDatabase, five tests each, which is 50 tests.
Laravel's own testing guide shows feature tests that boot the framework, so real tests are slower than my toy ones, so I added a beforeEach that sleeps 25 milliseconds. That makes a plain run take about 6.6 seconds instead of 0.8. The padding is mine and it favors TIA, because a bigger suite makes every avoided test worth more. Read the absolute seconds as illustrative and the replay counts as the real result.
I ran every scenario from a warm TIA state. For each one I reset the repository with git, ran Pest twice to record and settle, applied one edit, ran once more, and wrote down the wall time and how many tests Pest said it replayed. Coverage came from the Xdebug build that ships with Laravel Herd, loaded for the Pest process only.

How long does a Pest 5 TIA run take after each kind of edit?
A warm TIA run with no relevant change finishes in about half a second, against 6.6 seconds for a plain run of the same suite. After an edit, the time you pay is set by how many feature tests the edit touches. Here are all eleven results.
| Edit | Tests replayed | Wall time. |
|---|---|---|
| No change at all | 200 of 200 | 0.53 s. |
| Comment text in one service class | 200 of 200 | 0.66 s. |
composer.json description field |
200 of 200 | 0.65 s. |
.env.example new line |
200 of 200 | 0.66 s. |
| Behavior-preserving change in one service | 195 of 200 | 1.34 s. |
ArticleController rewritten, same behavior |
150 of 200 | 5.18 s. |
Article model cast renamed |
150 of 200 | 4.93 s. |
| Migration gets a nullable column | 150 of 200 | 4.94 s. |
New route in routes/web.php |
150 of 200 | 5.06 s. |
config/app.php timezone |
150 of 200 | 5.08 s. |
phpunit.xml new env value |
0 of 200 | 10.99 s. |
tests/Pest.php shared hook |
0 of 200 | 10.82 s. |
Three patterns stand out.
Advertisement
First, edits that only one class cares about are cheap. Changing Service05 reran its own five tests and nothing else. That is the case the marketing describes, and it was nearly five times faster than a full run.
Second, anything in the web path pulls in every feature test. The controller, the model, the migration, the routes file and the app config each reran all 50 database tests. Those 50 tests cost 5 seconds of my padded 6.6, so TIA saved only about a quarter of the time on those edits. That makes sense, since each of those files really is used by every HTTP test. It is still worth knowing before you promise your team a five-second suite.
Third, a change to the test harness is a full rerun plus overhead. Editing phpunit.xml or the shared tests/Pest.php invalidated everything, and the run took 10 to 11 seconds because Pest re-recorded the whole graph. The plain run is 6.6 seconds; so a harness change costs you about four extra seconds once.
How much does the first TIA run cost?
The first run that records the dependency graph took 9.4 seconds in my first measurement and between 10 and 10.6 seconds in later ones, against 6.6 seconds for a plain run. That is roughly 1.5 times slower, and you pay it once per fresh graph.
The reason is the coverage driver. A coverage driver is a PHP extension, such as Xdebug or PCOV, that records which lines of code run during a test. TIA needs line-level coverage to know which files each test used, and collecting coverage with Xdebug slows PHP down. The payback is quick. After the recording run, a typical service-level edit saves five seconds, so the investment is repaid on the second or third run.

Why did TIA do nothing on my machine?
TIA does nothing, without failing, when your PHP has no coverage driver. In my lab the first attempt returned a normal passing result with one extra line: "Running in TIA mode, however TIA is skipped as it needs ext-pcov or Xdebug." The run took the full time and replayed nothing.
If you run Pest from a script or an AI agent, that line is easy to miss. Pest detects agent environments and prints a one-line JSON summary instead of the usual report, and in that mode the "replayed" count is absent entirely. I had to unset the agent environment variables to see lines like Tests: 200 passed (380 assertions, 200 replayed).
TIA has a second quiet requirement. The first attempt failed outright with a missing-dependency message until I ran git init, because TIA uses git to see which files changed. You need both of these in CI.
# Local machine: load a coverage driver for the one command
php -d zend_extension=xdebug.so -d xdebug.mode=coverage vendor/bin/pest --tia
# Wipe and re-record the dependency graph
vendor/bin/pest --tia --fresh
# See the replay count: run from a normal terminal, or unset AI_AGENT and CLAUDECODE first
vendor/bin/pest --tia
If you use PCOV instead, install it with PECL and enable it for the CLI. Either driver works. Pest also has a CI baseline option, --tia --baselined, which fetches a shared graph recorded on your main branch. According to the Pest 5 release coverage, that baseline works with GitHub and an authenticated GitHub CLI only. I could not test it from a scratch directory, so I am not going to claim results for it.
Can TIA miss a failing test?
Yes, in one case I could reproduce. When I edited a model that had only a one-line declaration, TIA treated just 5 of the 50 tests that use it as affected. I then made the model throw on creation; a full run failed 30 tests. TIA reported 3 failures and replayed the rest as passing.
That result alarmed me, so I checked whether it was an artifact of my toy model. I rewrote Article the way real models look, with a casts() method that runs each time a model is built, and recorded a fresh graph. This time I broke the cast; the full run failed 10 tests and TIA failed the same 10, with all 50 database tests marked affected.
My reading is that TIA attributes a file to the tests that actually executed lines in it. A file whose only executable line runs once per process, when the autoloader first loads the class, gets attributed to the first test that loaded it. I have not read the Pest source to confirm that, so treat it as a hypothesis; the behavior is real either way.
Skipping tests always trades a little safety for speed. A team at Facebook studied this trade for machine-learned test selection and reported, in the Predictive Test Selection paper on arXiv, that their approach halved testing infrastructure cost while still reporting over 95 percent of individual test failures and over 99.9 percent of faulty changes. Pest's selection is dependency-based rather than learned, so those numbers do not transfer, but the lesson does: measure what a selection tool misses before you trust it.
What this means in practice:
- Files that are mostly declarations, such as simple enums, constant classes, and models with no methods, are the likeliest to be under-tracked.
- A full run on your main branch catches whatever a TIA run replayed by mistake. Do not make TIA your only gate.
- Keep one scheduled
--no-tiarun, nightly for example, as a net under the faster loop.
I tested two other things that matter for trust. Editing composer.json descriptions and .env.example caused no reruns, which is correct, since tests do not read those files. I did not test composer.lock changes or a new dependency, so I can't tell you how Pest handles those.
Should you upgrade to Pest 5 on Laravel 12?
No. The Pest 5 Laravel plugin requires laravel/framework ^13.23.0, which I confirmed with composer show pestphp/pest-plugin-laravel against the Packagist listing. A Laravel 12 project cannot install it, so the search term "pest 5 upgrade laravel 12" ends at this: stay on Pest 4.7 until you move to Laravel 13.
On Laravel 13 the upgrade has one trap that was not in any write-up I read; a fresh Laravel 13.35 skeleton pins phpunit/phpunit to ^12.5.12. Running composer require pestphp/pest:^5.0 --dev fails with a conflict, because Pest 5.3.1 needs phpunit/phpunit ^13.4.1; ask for both packages in one command.
composer require pestphp/pest:^5.0 pestphp/pest-plugin-laravel:^5.0 phpunit/phpunit:^13.4 --dev -W
Pest 5 also requires PHP 8.4, as composer show pestphp/pest lists. Laravel 13 itself still runs on PHP 8.3, so check your server and CI image before you bump anything. Then read the PHPUnit 13 changelog, since the announcement post names PHPUnit 13 as the main upgrade friction.
After installing, my 200 tests passed without edits. Nothing in my suite used deprecated PHPUnit features, so a larger suite may need changes.
When is TIA worth switching on?
TIA is worth switching on for local development and for the inner loop, and worth skipping for your final CI gate. In my lab it paid back within two or three runs, and the speedup was biggest exactly where developers spend most of their time, in service and domain code.
| Situation | My recommendation. |
|---|---|
Local pest --tia while coding |
Use it. Warm runs took 0.5 to 1.3 seconds on service edits. |
| Pull request CI | Use --no-tia, or use a baseline only if you are on GitHub. |
| Main branch and nightly | Full --no-tia run to catch replay mistakes. |
After touching phpunit.xml or Pest.php |
Expect a full rerun and a slower run. |
| Suites that finish in under 10 seconds | Skip it. The recording cost eats the gain. |
My lab suite is small, and a larger suite scales differently; if every test hits the database, then edits to the HTTP path will rerun almost everything. If your suite is mostly unit tests, you get close to the vendor figure.
What are the limits of this test?
The limits matter here; it was one synthetic app with 200 short tests, and the padding is artificial. I ran the full matrix twice. The replay counts agreed on every edit except the model one, which I changed between rounds, and wall times varied by a few tenths of a second. I used the Xdebug build from Herd, and PCOV may record at a different speed. I did not test Pest 5 features other than TIA: the agent plugin, the evals plugin and the browser plugin are outside this post.
About the author: I build Laravel applications and ran every command here on a scratch project in October 2026. The numbers were fact-checked against the saved run output. If a result does not reproduce for you, tell me through the contact page and include your PHP and Pest versions.
For related testing work, see my posts AI QA Testing in Laravel: 3 Bugs Only a Browser Test Sees and PHPStan Found 3 of 11 Laravel Bugs. AI Found 9 to 11.
The bottom line
Pest 5 TIA is a real speedup for service-level edits and a modest one for anything on the HTTP path. On Laravel 13, install Pest and PHPUnit 13 together, load a coverage driver, and keep a full run on main. On Laravel 12, wait.
The number to remember is not 3 minutes to 5 seconds. It is that one line of config or a single shared hook can make a TIA run slower than not using TIA at all.
Advertisement
FAQ
Can I upgrade to Pest 5 on Laravel 12?
No. The Pest 5 Laravel plugin requires laravel/framework 13.23 or newer, so a Laravel 12 project cannot install it. Stay on Pest 4.7 until you move to Laravel 13, which also needs PHP 8.3 or newer, and PHP 8.4 for Pest 5 itself.
Why does composer require pestphp/pest 5 fail on a new Laravel 13 app?
The Laravel 13.35 skeleton pins phpunit/phpunit to ^12.5.12, while Pest 5.3.1 needs PHPUnit 13.4.1. Require both in one command, with phpunit/phpunit:^13.4 and the -W flag, and Composer resolves the pair cleanly. The Laravel plugin also needs version 5.0 or newer.
Why does Pest TIA run every test or skip itself?
TIA needs git and a coverage driver such as Xdebug or PCOV. Without the driver Pest prints a one-line notice and runs normally. Edits to phpunit.xml or tests/Pest.php invalidate the whole dependency graph and rerun everything, and that run is slower than a plain one.
Can Pest TIA miss a failing test?
Yes, in one case I reproduced. A model file with only a one-line declaration was attributed to a single test file, so breaking it failed 3 tests instead of 30. A model with a method that runs every time was tracked correctly. Keep a full nightly run.
Comments
Loading…
Sign in to join the conversation.
Related posts

Laravel LSP in Neovim: Setup and What It Skips
Laravel LSP gives any editor that speaks the Language Server Protocol the same Laravel autocomplete that VS Code users already had. I installed version 0.0.32 and drove it with a protocol client
Sat Oct 10 2026 · 10 min read · 0 views

Laravel Cloud Scale to Zero: What an Idle App Costs
A mostly idle Laravel app on Laravel Cloud's Starter plan bills about $5 a month, and the compute behind four awake hours is roughly 4 cents. Scale to zero removes the cost of idle compute. It does
Sat Oct 10 2026 · 10 min read · 0 views

Laravel CVE-2026-102279: Which Version Fixes It?
Laravel 13.30.0 and Laravel 12.69.0 fix CVE-2026-102279, a cross-site scripting bug in the exception debug page. Those same two versions also contain the fixes for the two other Laravel framework
Sat Oct 10 2026 · 10 min read · 0 views