Drupal tip of the day: PHPUnit 6 tests with composer-project/drupal-project

Submitted by Frederic Marand on

The problem

When trying to run PHPUnit tests on the MongoDB contrib module for the soon-ready 8.2.0 version, I recently starting encountering this error:

PHPUnit testing framework version 6 or greater is required when running on PHP 7.0 or greater.
Run the command 'composer run-script drupal-phpunit-upgrade' in order to fix this.

OK, no big deal, let's just run that command.

# From $PROJECT/web/core directory
$ ../../vendor/bin/composer run-script drupal-phpunit-upgrade

In RunScriptCommand.php line 89:

Script "drupal-phpunit-upgrade" is not defined in this package
run-script [--timeout TIMEOUT] [--dev] [--no-dev] [-l|--list] [--] [] []...
$

Hmm, so I need that command but it is not defined in composer.json. So where is it ?

$ cd $PROJECT
grep -ir drupal-phpunit-upgrade .
./web/core/tests/bootstrap.php: $message = "PHPUnit testing framework version 6 or greater is required when running on PHP 7.0 or greater. Run the command 'composer run-script drupal-phpunit-upgrade' in order to fix this.";
./web/core/tests/README.md:- If you're running PHP 7.0 or greater you will need to upgrade PHPUnit with `composer run-script drupal-phpunit-upgrade`
./web/core/scripts/run-tests.sh: simpletest_script_print_error("PHPUnit testing framework version 6 or greater is required when running on PHP 7.0 or greater. Run the command 'composer run-script drupal-phpunit-upgrade' in order to fix this.");
./web/core/scripts/run-tests.sh: passthru("$composer run-script drupal-phpunit-upgrade-check");
./web/core/lib/Drupal/Core/Composer/Composer.php: * Fires the drupal-phpunit-upgrade script event if necessary.
./web/core/lib/Drupal/Core/Composer/Composer.php: // call the drupal-phpunit-upgrade script to upgrade PHPUnit.
./web/core/lib/Drupal/Core/Composer/Composer.php: ->dispatchScript('drupal-phpunit-upgrade');
$

So that command is referenced in multiple places, but defined nowhere. What's going on ?

The diagnostic

Most of the time, when building Drupal 8 projects, we want to use the  drupal-project package, to get a saner project layout. But when contributing to core, the common practice has long been to use either drupal/drupal or even just a Git checkout of Drupal itself. Things are likely to change on that front when issue #2982674 is fixed, though.

At the same time, PHP versions continue moving, with the now-current version being PHP 7.1.x for most cases, and PHP 7.2.x the target version for this autumn. And PHPunit 4.x, which served us faithfully for years, is not compatible at all with PHP 7.2, so the migration to PHPunit 6.x has been required since Issue #2927806 in april 2018. And is now used for 7.0.x/7.1.x too as detailed in https://www.drupal.org/node/2957906.

But on the other hand, composer-project/drupal-project provides a composer.json script which does not include the drupal-phpunit-upgrade, arguably because it still generates a Drupal 8.5.x version these days, which causes this command to fail.

The expected non-working fix

Until issue #2982674 makes it, or drupal-scaffold is updated, what we should just need here is the command as it appears in the composer.json for current Drupal core 8.7.x:

     "drupal-phpunit-upgrade": "@composer update phpunit/phpunit --with-dependencies --no-progress",

Let's just add it to composer.json and check PHPunit: still version 4.8.x ! The problem is that composer-project adds a phpunit dependency to 4.8.36, which installed and locked earlier versions, for which Composer cannot find an update path.

The actual fix

Actually, projects do no longer need this line, because of the webflo/drupal-core-require-dev dependency, which itself requires phpunit/phpunit (^4.8.35 || ^6.5), which would allow PHPunit 6.x, unlike what our base composer.json requires. So let's just remove the direct dependency on PHPunit currently locking us to 4.8.

$ composer remove --dev phpunit/phpunit
# ...lots of lines showing the upgrade...
$ vendor/bin/phpunit --version
PHPUnit 6.5.9-3-g2d53bd5ae by Sebastian Bergmann and contributors.
$ composer why phpunit/phpunit
webflo/drupal-core-require-dev  8.6.x-dev  requires  phpunit/phpunit (^4.8.35 || ^6.5)
$

As these results show, we now have a PHPunit 6.x, thanks to webflo's package. Problem solved.