psalm/plugin-phpunit
A Psalm static analysis plugin that understands PHPUnit test classes, mocks, and data providers.
Repository Health
Technical Analysis
psalm/plugin-phpunit extends the Psalm static analyzer with PHPUnit-specific type inference so PHPUnit test suites produce far fewer false-positive errors. It registers a stub file for PHPUnit’s TestCase and a set of hooks that understand mock objects, data providers, and assertion methods like assertInstanceOf and assertTrue in ways Psalm cannot infer from PHPUnit’s own generic signatures.
Installed as a dev-only composer dependency and enabled via vendor/bin/psalm-plugin enable psalm/plugin-phpunit, it is one of the most widely used Psalm plugins in the PHP ecosystem, pulling over 300k monthly downloads because nearly every Psalm-analyzed codebase that uses PHPUnit needs it to avoid analyzer noise in its test directory.
What You Get
- A TestCase stub file that describes PHPUnit’s TestCase API more precisely than PHPUnit’s own PHPDoc allows
- A TestCaseHandler hook class that recognizes assertion methods (assertInstanceOf, assertTrue, assertNull, etc.) and narrows variable types accordingly
- Support for mock object type inference so createMock()-generated doubles are typed against the mocked class
- A conflict rule enforcing compatible PHPUnit and Prophecy versions to avoid silently broken hooks
- Zero runtime footprint — it only affects
psalmanalysis output, never the code that actually runs
Common Use Cases
- Adding it to a PHP project that already runs Psalm so PHPUnit test files stop generating spurious PossiblyUndefinedMethod or MixedAssignment errors
- Enabling type narrowing after assertInstanceOf()/assertNotNull() calls so downstream test code gets accurate autocompletion and analysis
- Reducing @psalm-suppress annotations scattered through a test suite by letting the plugin infer types the analyzer would otherwise miss
- Standardizing static analysis coverage across both application code and its PHPUnit-based test suite in one Psalm run
Under The Hood
Architecture — The plugin is a thin adapter around Psalm’s plugin API: Plugin.php implements PluginEntryPointInterface and registers two things at Psalm startup — a stub file (stubs/TestCase.phpstub) providing a more precise signature for PHPUnit’s TestCase, and Hooks/TestCaseHandler.php, a ~650-line class implementing Psalm’s after-method-call and after-expression hook interfaces to intercept calls like assertInstanceOf, assertTrue, and createMock inside test methods and adjust Psalm’s internal type context. Tech Stack — PHP 8.1+, built against psalm/psalm-plugin-api (the stable plugin contract, decoupled from Psalm’s own release cadence) and requiring vimeo/psalm dev-master or ^6.10 for development; testing uses Codeception with an acceptance suite plus a Behat-based CLI harness under tools/behat rather than plain PHPUnit unit tests, since the plugin’s own behavior is best verified by running Psalm against fixture code and asserting on its output. Code Quality — The two-file src/ layout (Plugin.php as the entry point, TestCaseHandler.php as the sole hook implementation) keeps the logic centralized and easy to audit; phpcs enforces style and the project runs psalm on itself via the analyze composer script, meaning the analyzer plugin is dogfooded against its own codebase. API Design — Consumer-facing surface is minimal by design: install via composer, run one psalm-plugin enable command, and the plugin activates transparently with no configuration required, which is exactly the right shape for a static-analysis extension that should be invisible when working correctly.