We're upgrading from Laravel 9 to 10, and PHPUnit 9 to 10, and, if all goes well, we'll top it off by migrating to Pest, the latest version. To keep the positive vibes on I'll skip an upgrade from PHP 8.1 to 8.2, just because I don't want to restart Docker in the production server for now. Sunday is for safe stuff only.
Remove or upgrade outdated packages
Firstly, check the dependencies guide here, and complete all the steps outlined in that section. You need to update the composer.json with the new versions, and then run composer update
. It will fail, most probably. The error logs will show you which packages are incompatible or need to be updated to support the latest version.
I was using some packages that were deprecated or didn't have support for Laravel 10 as of now. Luckily, in my very specific case, I didn't really need or use them, so I just removed them. The two packages were:
CORS Middleware for Laravel - all supported Laravel versions now include the CORS middleware in the core.
Laravel Slack - helper package to make Slack notifications easier to send. I wasn't making good use of this package, and Laravel has built-in logging to Slack anyway.
After you've handled this step according to your specific case, you should now have a clean installation of Laravel 10. I'd make a commit for it.
Install Rector for Laravel
Rector will help us migrate to the new Laravel version with practically no effort. Follow the Composer installation guide here, and then install the Laravel extension. Among other configurations you might have in your rector.php
file, add the Laravel 10 set:
use Rector\Config\RectorConfig;
use RectorLaravel\Set\LaravelSetList;
return static function (RectorConfig $rectorConfig): void {
$rectorConfig->sets([
LaravelSetList::LARAVEL_100,
]);
};
Now just run vendor/bin/rector process
and see what happens. It will handle most of the changes for you, like model "dates" property, the Bus
facade's dispatchNow
to dispatchSync
, etc. At this point, I make another commit to separate the automatic changes from my own changes.
Add the finishing touches to the upgrade
As a final step, take a good look at the upgrade guide for anything that needs your attention. There are certain things that Rector can not cover for you, like moving lang
files around. You're not entirely out of luck though, there's a paid service called Shift, that has that capability and is tailored for Laravel projects. I suggest you give it a chance to prove itself, it's worth every penny. But still, double-check with the upgrade guide and see if anything's missing.
Make another commit for it if you've made any changes, and run your tests. Hopefully, everything's green.
Upgrade to PHPUnit 10
Update your PHPUnit version to "phpunit/phpunit": "^10"
and run a composer update
. It will probably go smoothly. The first time you'll run your tests, it will ask you to update your phpunit.xml
schema to a newer version, you should run a command for that. Run it: ./vendor/bin/phpunit --migrate-configuration
.
In your rector.php
file add the PHPUnit rule:
use Rector\Config\RectorConfig;
use Rector\PHPUnit\Set\PHPUnitSetList;
use RectorLaravel\Set\LaravelSetList;
return static function (RectorConfig $rectorConfig): void {
$rectorConfig->paths([
__DIR__ . '/app',
__DIR__ . '/database',
__DIR__ . '/tests',
]);
$rectorConfig->sets([
LaravelSetList::LARAVEL_100,
PHPUnitSetList::PHPUNIT_100,
]);
};
Don't forget to include your tests directory in the paths that Rector will look for. Run ./vendor/bin/rector
again and see what happens. All your tests will be migrated to the new Attributes syntax, and your data providers will be made static. If you run your tests now they should all pass, unless you've written some suspicious test classes and used $this
inside your data providers, as I did ๐. And now's the time for another commit.
Migrate to Pest v2
Pest has a migration tool of its own, it's called Drift, and it's a Pest Plugin. You can install it with composer require pestphp/pest-plugin-drift --dev
. To convert all your tests you simply run ./vendor/bin/pest --drift
. It will remove all classes of your tests, rename the tests to use spaces instead of snake case or camel case, and convert most of the assertions to the expectation APIs.
Depending on your test structure, there might be some more work involved. For example, you might have tests in directories other than Feature or Unit, like Billing, etc. You can either specify the directories one by one in your Pest.php
file, or include the whole directory to use the correct TestCase
with a single line:uses(\Tests\TestCase::class)->in('./');.
The migration will remove all classes in your tests, so if you had private
helper methods, they will be converted to functions. Inside those functions, you lose access to the $this
variable, so you must check each case and fix it manually, at least at the time of this post. For example, instead of $this->mock(...)
you have to use just mock(...)
.
And now you should be good to go. Probably all or most of your tests are green.