Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Rector Phpunit Laravel Package

rector/rector-phpunit

Rector rules for PHPUnit that automate test suite upgrades. Modernize assertions, replace deprecated APIs, and keep tests compatible across PHPUnit versions through automated, configurable refactoring—no manual edits required.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the rules alongside Rector as dev-only dependencies:

composer require --dev rector/rector rector/rector-phpunit

Create a rector.php at the project root, scoped to your test directory so it never touches src/:

<?php
// rector.php
use Rector\Config\RectorConfig;
use Rector\PHPUnit\Set\PHPUnitSetList;

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/tests'])
    ->withSets([PHPUnitSetList::PHPUNIT_100]);

Always preview before applying:

vendor/bin/rector process --dry-run --diff
vendor/bin/rector process

First use case: modernizing a legacy suite. The single most valuable thing this package does is take a PHPUnit 8/9 test suite and mechanically rewrite it for PHPUnit 10/11 — annotations to attributes, getMock() → createMock(), assertFileNotExists() → assertFileDoesNotExist(), expectExceptionMessageRegExp → expectExceptionMessageMatches, and the removal of withConsecutive(). Start there: pick the set one major version ahead of your current phpunit/phpunit constraint, dry-run, review the diff, then bump the constraint and run the tests.

Look first at PHPUnitSetList in the package source (or the README) — that's your menu. Available sets cover PHPUNIT_60 through PHPUNIT_120 plus PHPUNIT_CODE_QUALITY, which contains non-version-specific cleanups like converting $this->assertSame(true, …) to assertTrue().

Implementation Patterns

Layered upgrades, one major version at a time. Never jump PHPUNIT_80 → PHPUNIT_110 in one go. Apply a set, commit, run the suite, then apply the next. Rector rules often depend on the syntax produced by the prior step.

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/tests'])
    ->withSets([
        PHPUnitSetList::PHPUNIT_90,
        // add PHPUNIT_100 next commit
    ]);

Combine with PHP-version rules. Upgrade the language and the testing framework in lockstep: withPhpSets(php82: true) before a PHPUNIT_100 pass, since PHPUnit 10 requires PHP 8.1+.

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/tests'])
    ->withPhpSets(php82: true)
    ->withSets([PHPUnitSetList::PHPUNIT_100])
    ->withImportNames(removeUnusedImports: true);

Target a single file while iterating. When a rule misbehaves on a 500-test suite, narrow the blast radius:

vendor/bin/rector process tests/Unit/OrderTest.php --dry-run --diff

CI guard against regressions. Run vendor/bin/rector process --dry-run as a CI job. Every time a developer reintroduces a deprecated assertion (copy-pasting an old test), the job fails with the exact fix. This is often more valuable long-term than the one-time migration.

Selective rules instead of full sets. If a set contains a rule you disagree with (e.g., a code-quality rule that aggressively inlines assertions), drop to withRules() for just the migrations you want:

use Rector\PHPUnit\PHPUnit100\Rector\Class_\AddProphecyTraitRector;

->withRules([AddProphecyTraitRector::class])

Pair with phpunit/phpunit in composer.json. The set you apply should correspond to the constraint you're moving to, not the one you're moving from. Update composer.json in the same PR so composer install and the rewritten tests agree.

Gotchas and Tips

Rector needs to recognize a file as a test. Many rules only fire on classes extending PHPUnit\Framework\TestCase or using PHPUnit attributes. If your base test class is in a separate package or uses a non-standard namespace, either add it via withBootstrapFiles() or accept that some rules silently skip the file. Symptom: a rule you expect to apply produces no diff.

PHPUnit 10 attribute conversion is imperfect. The @dataProvider → #[DataProvider] and @covers → #[CoversClass] rewrites work for clean docblocks but get confused by multi-line annotations, nested @covers/@coversNothing, or annotations combined with prose. Grep the diff for @dataProvider and @covers survivors and fix them by hand.

withConsecutive() is rewritten but not semantically safe. The rule converts to willReturnCallback()/willReturnOnConsecutiveCalls() variants, but argument-matching semantics can drift, especially with with() chained on it. Any test that used it deserves a manual re-read after the rewrite.

Cache masks config changes. If you edit rector.php and see no change in output, run vendor/bin/rector process --clear-cache. This catches nearly every "it did nothing" report.

Set constants drift across releases. PHPUnitSetList::PHPUNIT_120 may not exist in older rector/rector-phpunit tags. Pin the version in composer.json and check vendor/rector/rector-phpunit/config/sets/ to confirm the constant names available to you.

Don't let it run on src/. Production code should not be rewritten by PHPUnit-specific rules — they assume a test context. Keep withPaths([__DIR__ . '/tests']) strict, and add ->withSkip([__DIR__ . '/src']) as a belt-and-suspenders measure.

Base TestCase classes need manual attention. If you have an abstract AppTestCase that defines helpers like assertContainsValue(), rules can false-positive on calls to them. Use withSkip() at rule level or add a // no-rector style guard if the rule supports it; otherwise exclude the file.

Extension points. All rules extend Rector\Core\Rector\AbstractRector (or AbstractRector on Rector 1.x). You can write a project-local rule — e.g., to rename your own $this->assertJsonContains() helper — and register it with withRules([MyJsonAssertRector::class]). This is the clean way to handle custom test utilities that the package can't know about.

Run after, not before, formatting. Rector produces syntactically valid but unevenly formatted code. Run PHP-CS-Fixer/Pint after rector process on the same paths; if you run it before, Rector's rewrites will reintroduce style drift you just fixed.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect