Pest for PHP: a testing framework built on PHPUnit, not beside it
The elegant testing framework for PHP developers and AI agents.
At a glance
- What is it?
- Pest wraps PHPUnit in a functional syntax and ships as a Composer package. Here is what it changes for a PHP test suite, what the README leaves undocumented, and how it differs from plain PHPUnit.
- Who is it for?
- Adopt Pest if you already have a PHPUnit suite and want shorter test files without leaving the PHPUnit runner, or if you want the plugin packages for Laravel, Livewire, browser and architecture testing. Do not adopt it if you need a runner with no PHPUnit underneath, or if you are on a PHP version outside what the current release supports; the README does not state a minimum.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 12 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem Pest targets: PHPUnit's verbosity, not PHPUnit's engine
A PHPUnit test class carries a lot of ceremony. You write a class, extend TestCase, declare a public function, name it with a test prefix or annotate it, and repeat that shape for every case. Pest keeps the PHPUnit engine and replaces the authoring surface with functions. Tests are written with test() or it(), and expectations are chained off the value under test rather than asserted in a separate call.
The README describes Pest as "an elegant testing framework for PHP developers and AI agents." The audience claim is worth reading carefully. The first half is ordinary: PHP developers who find class-per-test boilerplate heavy. The second half points at something newer. The repository ships an AGENTS.md and a CLAUDE.md at the top level, alongside CONTRIBUTING.md and RELEASE.md. Those files are instructions for coding agents working inside the repository itself, which is a different thing from Pest being a testing tool for agent-generated code. Either way, the project is positioning itself for a workflow where an agent writes and edits test files, and a terser syntax gives an agent less structure to get wrong.
Who this is not for: anyone who wants a test runner that is independent of PHPUnit. Pest is not a replacement engine. It is a layer.
How Pest sits on top of PHPUnit: the mechanism visible in the repository
The repository layout is the clearest evidence of the architecture. There is a phpunit.xml at the top level, and pestphp/pest is distributed through Packagist. Pest does not fork the runner. It configures and extends PHPUnit, so the same phpunit.xml that drives a PHPUnit suite is the file Pest reads.
Two static-analysis extension files sit at the root: extension.neon, which is PHPStan's extension format, and phpstan-pest-extension.neon, plus phpstan.neon and phpstan-baseline.neon. That tells you the project treats static analysis of Pest test code as part of its own quality process, and it implies the expectation-based API needs type information that a plain PHPStan run would not have. There is also a rector.php and a pint.json, which are the project's own refactoring and formatting configuration.
The src/ directory holds the framework, stubs/ holds the files that get written into your project when you scaffold tests, and overrides/ plus tests-external/ suggest parts of the suite run against something outside the main tests/ tree. A docker/ directory and a bin/ directory round out the layout. The bin/ entry is what Composer exposes as the pest executable.
The practical consequence of this design: your existing PHPUnit assertions, fixtures and configuration do not have to be thrown away. A file written as a PHPUnit class and a file written with Pest functions can run in the same suite.
Installing Pest from Packagist and writing a first test
Pest is distributed as a Composer package. The README does not print an install command, so the package name is the reliable anchor: pestphp/pest, taken from the README's own Packagist badge links. Because it is a test runner, it belongs in the development dependency set.
The README also does not document a scaffolding command or a binary path, so there is nothing here to quote. The one install-adjacent fact the README does give is the documentation location: pestphp.com, linked twice in the README as the place to explore the docs. That page is where the installation steps, the configuration keys and the first-test walkthrough live. Consult it rather than relying on a command reproduced here.
What the repository layout does establish is the shape of a Pest project once it is set up. The root carries a phpunit.xml, which is the configuration file Pest reads. The stubs/ directory holds the files that get written into a consuming project when tests are scaffolded. The bin/ directory is what Composer exposes as an executable.
What the README does not show is sample console output, the exit-code convention, or a worked example of a passing test. None of that is documented in the repository's front page, and this article will not invent it. If you need a runnable first test before deciding, the pestphp.com docs are the only source named in the README.
Where the README is thin, and what that costs you
The README is a landing page, not documentation. It links to pestphp.com for the actual docs and says nothing about installation, configuration, minimum PHP version, or how to migrate an existing PHPUnit suite. That is a real gap for anyone evaluating the project from the repository alone.
The most consequential omission is version compatibility. The default branch is 5.x and the most recent releases are v5.1.4, v5.1.3 and v5.1.2. Nothing in the README states which PHP versions those releases support, and nothing states which phpunit/phpunit constraint they require. Because Pest layers over PHPUnit, that constraint is not a detail: it determines whether pestphp/pest can coexist with the PHPUnit version already pinned in your composer.json. You will find out during composer require, not before.
The second gap is migration. The README does not document how to convert a PHPUnit class to Pest functions, and it does not document rollback. If you convert a suite and want to revert, the README gives you nothing to follow. Because Pest runs on PHPUnit, reverting is a matter of restoring your files rather than changing engines, but that is an inference from the architecture, not a documented procedure.
The third gap is the plugin ecosystem. The README does not list the plugin packages, even though they are the reason many teams pick Pest in the first place.
The plugin packages are the real adoption argument
Pest's core is small. The value compounds through separately installed plugins, which the README does not enumerate but which appear in the search terms people use around the project: pest-plugin-laravel, pest-plugin-browser, pest-plugin-livewire, pest-plugin-type-coverage and pest-plugin-arch.
These are separate Composer packages, each covering a different testing concern. A Laravel plugin wires up the framework's test helpers. A browser plugin covers end-to-end interaction. A Livewire plugin targets that component library. A type-coverage plugin measures how much of your code is exercised by type assertions. An architecture plugin lets you assert structural rules about your codebase, such as which namespaces may depend on which.
That decomposition is a design choice with a cost. Each plugin is its own dependency with its own release cadence and its own compatibility window against the core. A team running Laravel, Livewire and browser tests is maintaining four Pest-related packages, not one. The README gives no compatibility matrix, so the burden of checking that the installed plugin versions match the core version falls on you.
The upside is that a plain PHP project with no framework can install the core alone and carry nothing extra.
Pest against plain PHPUnit: the same engine, a different authoring surface
The honest alternative is PHPUnit itself, and the comparison is unusual because Pest does not compete with PHPUnit at runtime. Pest runs on it. The difference is entirely in how tests are written and how much configuration you maintain.
With PHPUnit you write a class per test file, extend TestCase, and use assertion methods. With Pest you write functions and chain expectations. The second style produces shorter files, and shorter files are easier for a tool or an agent to generate and edit. That is the whole trade.
What you give up by choosing Pest is the directness of the PHPUnit documentation. When something breaks inside the runner, the stack trace leads into PHPUnit, and the PHPUnit docs are the ones that explain it. Pest adds a layer that the PHPUnit documentation does not describe. You are also depending on a project whose compatibility with PHPUnit is maintained by its authors, not guaranteed by PHPUnit's own release process.
The repository's phpunit.xml at the root is the tell. Pest is configured through PHPUnit's configuration file, which means anyone who already understands phpunit.xml can read a Pest project's configuration without learning anything new.
Maintenance, licensing and what an upgrade actually involves
The repository is not archived, and the last push was on 2026-09-09. The most recent release, v5.1.4, was published on 2026-09-07, with v5.1.3 and v5.1.2 both landing on 2026-08-25. The 5.x line is receiving patch releases at a steady clip.
Pest is licensed under the MIT license, per the README and the LICENSE.md file in the repository. MIT is permissive: it allows commercial use, modification and redistribution, and it requires that the licence text and copyright notice travel with the code. That is a description of the licence terms, not legal advice; if your organisation has rules about which licences may enter a dependency tree, run Pest through that process rather than relying on this summary.
The upgrade cost is the part worth thinking about before you adopt. Because Pest sits on PHPUnit, a Pest major version bump can move the underlying PHPUnit constraint, and that can collide with whatever your application or framework pins. The repository carries a phpstan-baseline.neon, which is the standard way a PHP project records known static-analysis errors it has not fixed yet; a baseline file existing is normal and says nothing about the project's health either way. What it does tell you is that the codebase is checked with PHPStan, and Pest ships its own PHPStan extension so that expectation chains are understood by the analyser. If you run PHPStan in CI, you will want that extension registered, or your Pest test files will produce analysis noise.
Editorial conclusion
Adopt Pest if you already have a PHPUnit suite and want shorter test files without leaving the PHPUnit runner, or if you want the plugin packages for Laravel, Livewire, browser and architecture testing. Do not adopt it if you need a runner with no PHPUnit underneath, or if you are on a PHP version outside what the current release supports; the README does not state a minimum. Before committing, verify three things on your own machine: that pestphp/pest resolves against your existing phpunit/phpunit constraint in composer.json, that your CI configuration still points at a binary that exists after install, and that any test relying on PHPUnit-only APIs still passes once the suite runs through Pest.
Frequently asked questions
What is the Pest PHP testing framework?
The README describes Pest as an elegant testing framework for PHP developers and AI agents. It is distributed as the pestphp/pest Composer package and is licensed under MIT.
How do I install Pest in a PHP project?
The README does not print install steps; it points to pestphp.com as the place to explore the documentation. The package is published on Packagist under the name pestphp/pest, which is the anchor the README's own badge links use.
Does Pest replace PHPUnit?
No. The repository contains a phpunit.xml at the top level and the package is distributed through Packagist, which indicates Pest is configured through and runs on PHPUnit rather than replacing its engine. The README does not state a PHPUnit version constraint.
Which Pest plugins exist for Laravel, Livewire and browser testing?
The search terms around the project name pest-plugin-laravel, pest-plugin-browser, pest-plugin-livewire, pest-plugin-type-coverage and pest-plugin-arch. The README does not list or document the plugin packages, and it gives no compatibility matrix between plugin versions and the core version.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pestphp-pest)