Time to share some experiences with getting something up and running. This time getting PHPUnit to work under Drupal8 on Windows.
PHPUnit
I started reading PHPUnit in Drupal and the PHPUnit manual, downloaded the PHPUnit phar file and performed some PHPUnit only tests until things started to work. The examples on the PHPUnit website where a bit flawed especially the one with the CsvFileIterator class as it turns out PHP’s fgetcsv() nicely returns integer values yet the testAdd method is called with the integer converted to strings.
I had to modify the example to
public function testAdd($a, $b, $expected): void
{
// additionProvider returns integers, but PHPUnit’s invocation
// of testAdd() seems to receive strings.
// Note: The csv file should have a trailing crlf.
$this->assertSame($expected+0, $a+0 + $b+0);
}
in order to force a conversion to numbers again so the assertion can do it’s job.
Another observation is that annotations are important. For example adding
@covers <something>
to a methods comment silences the ‘Risky’ test warnings. Finally it’s important to create a phpunit.xml file in the folder from where you start PHPUnit to run the tests. Running the tests is a matter of a command alike:
php phpunit.phar <relative path where to look for tests>
The CsvFileIterator example I got working by specifying the CsvFileIterator.php as bootstrap in the phpunit.xml file (a workaround). An alternative might be adding a line to the Unit Test alike:
include(dirname(__FILE__).”/../../src/CsvFileIterator.php”);
assuming the relative path to CsvFileIterator.php file is correct.
Drupal8
Getting things to run under Drupal8 was a different adventure.
I started with using the PHPUnit version I downloaded (the latest version) and it looked promising. I was able to run my standalone examples after adding them into a Drupal custom module I planned to write tests for.
The problems started when I wanted to access a simple class method in the module. First it looked simple as a namespace issue (understandable as the test suite wasn’t going to load Drupal code without it being correct). Using the examples on the Drupal8 website I corrected namespaces and moved the test suite into the correct location.
The Unit Test namespace should look as:
namespace Drupal\Tests\<custom module>\Unit;
The Unit Test class documentation should look as:
/**
* @coversDefaultClass \Drupal\<custom module>\<custom module class>
* @requires module <custom module>
* @group Unit
*/
The test class should extend UnitTestCase instead of TestCase (something I discovered later). The test class location should be:
modules\<custom module>\tests\Unit\ControllerServiceTest.php
Note the Unit in the path/namespace and the base class depends on the type of test being implemented.
Finally it’s important to copy the phpunit.xml.dist file out of the core folder and rename it to phpunit.xml. If you leave the phpunit.xml file in the core folder it will get deleted when the core is updated with composed. Finally edit the phpunit.xml file, correct the path to the Bootstrap.php file to bootstrap=”core/tests/Bootstrap.php” and uncomment the ini tags and specify the correct values for your Drupal8 installation.
But even with this all done, calling a method on a custom module class still failed miserably with some vague messages about missing classes in PHPUnit. Searching for them which normally works to get a clue about what’s wrong totally failed this time, suggesting nobody had this issue and the missing classes just did not exist.
After re-reading quite some webpages I came across this text on the first page I read starting this adventure:
“We use multiple versions of PHPUnit in the DrupalCI on drupal.org. E.g. on PHP 5.5, 5.6, 7.0 and 7.1 we use PHPUnit 4.8. On PHP 7.2 we use PHPUnit 6.5. It is discouraged to use PHP versions which are out-of-life on production (documentation about supported PHP versions).”
Although I though it was a long shot (I was using PHP 7.3 for example), I started looking into how to get an older version of PHPUnit installed.
composer require –dev phpunit/phpunit ^6.5
Although I’m no fan of composer this finally worked. Installing a newer version using
composer require phpunit/phpunit
gets you into trouble when downgrading as one of the dependencies prevents a direct downgrade without first removing it.
Finally my test code creating a class from the custom module and invoke a simple method worked:
The command:
php vendor\phpunit\phpunit\phpunit .\modules\<custom module>
from the Drupal8 root folder now nicely executes the test:
<?php declare(strict_types=1);
namespace Drupal\Tests\<custom module>\Unit;
use Drupal\Tests\UnitTestCase;
use Drupal\<custom module>\Form\StudyMessage;/**
* @coversDefaultClass \Drupal\<custom module>\StudyMessage
* @requires module <custom module>
* @group Unit
*/
final class ControllerServiceTest extends UnitTestCase {
$service = new StudyMessage();
$this->assertIsObject($service);
$this->assertInstanceOf(StudyMessage::class, $service);
fwrite(STDOUT, $service->getFormId() . “\n”);
$this->assertSame($service->getFormId(),”XYZ”);
}