Running tests for PHPUnit itself from within PhpStorm

Würzburg, Germany

Have you been working on phpunit/phpunit? Are you a user of PhpStorm?

I have and I am, and until yesterday I have been struggling with setting up phpunit/phpunit as test framework for PhpStorm so I can run tests for phpunit/phpunit from within PhpStorm for phpunit/phpunit itself.

Use Composer autoloader

In any project that requires phpunit/phpunit as a development dependency, the setup is fairly simple: pick the Use Composer autoloader option and reference the path to vendor/autoload.php.

However, for phpunit/phpunit this will not work, as it does not have a dependency on itself:

Use composer autoloader

Path to phpunit.phar (with downloaded phpunit.phar)

Ok, then, let’s try the option Path to phpunit.phar!

Looks like we need to download phpunit.phar here, so let’s head over to Getting Started with PHPUnit 8 and find out how to download phpunit.phar`.

Personally, I ran

$ wget -O ~/Sites/phpunit.phar https://phar.phpunit.de/phpunit.phar
$ chmod +x ~/Sites/phpunit.phar

Next, I pick the Path to phpunit.phar option and specify the path to the previously downloaded phpunit.phar:

Path to phpunit.phar (with downloaded phpunit.phar)

Looks like that worked fine, now let’s run the tests by right-clicking on phpunit.xml, and selecting the option Run ‘phpunit.xml’.

Great, the tests run! But they fail with

Testing started at 11:25 ...
/usr/local/Cellar/php@7.2/7.2.17_1/bin/php /Users/am/Sites/phpunit --configuration /Users/am/Sites/sebastianbergmann/phpunit/phpunit.xml --teamcity
PHPUnit 8.1.3 by Sebastian Bergmann and contributors.

Runtime:       PHP 7.2.17 with Xdebug 2.7.1
Configuration: /Users/am/Sites/sebastianbergmann/phpunit/phpunit.xml


TypeError : Return value of PHPUnit\Framework\Constraint\Count::getCountOf() must be of the type integer or null, none returned
 phar:///Users/am/Sites/phpunit/phpunit/Framework/Constraint/Count.php:86
 phar:///Users/am/Sites/phpunit/phpunit/Framework/Constraint/Count.php:44
 phar:///Users/am/Sites/phpunit/phpunit/Framework/Constraint/Constraint.php:45
 /Users/am/Sites/sebastianbergmann/phpunit/tests/unit/Framework/Constraint/CountTest.php:164
 phar:///Users/am/Sites/phpunit/phpunit/Framework/TestCase.php:1172
 phar:///Users/am/Sites/phpunit/phpunit/Framework/TestCase.php:854
 phar:///Users/am/Sites/phpunit/phpunit/Framework/TestResult.php:685
 phar:///Users/am/Sites/phpunit/phpunit/Framework/TestCase.php:808
 phar:///Users/am/Sites/phpunit/phpunit/Framework/TestSuite.php:761
 phar:///Users/am/Sites/phpunit/phpunit/Framework/TestSuite.php:761
 phar:///Users/am/Sites/phpunit/phpunit/Framework/TestSuite.php:761
 phar:///Users/am/Sites/phpunit/phpunit/TextUI/TestRunner.php:601
 phar:///Users/am/Sites/phpunit/phpunit/TextUI/Command.php:207
 phar:///Users/am/Sites/phpunit/phpunit/TextUI/Command.php:163
 
PHP Fatal error:  Class Mock_Exception_19a384fc contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (ExceptionWithThrowable::getAdditionalInformation) in phar:///Users/am/Sites/phpunit/phpunit/Framework/MockObject/Generator.php(608) : eval()'d code on line 1
PHP Stack trace:
PHP   1. {main}() /Users/am/Sites/phpunit:0
PHP   2. PHPUnit\TextUI\Command::main() /Users/am/Sites/phpunit:619
PHP   3. PHPUnit\TextUI\Command->run() phar:///Users/am/Sites/phpunit/phpunit/TextUI/Command.php:163
PHP   4. PHPUnit\TextUI\TestRunner->doRun() phar:///Users/am/Sites/phpunit/phpunit/TextUI/Command.php:207
PHP   5. PHPUnit\Framework\TestSuite->run() phar:///Users/am/Sites/phpunit/phpunit/TextUI/TestRunner.php:601
PHP   6. PHPUnit\Framework\TestSuite->run() phar:///Users/am/Sites/phpunit/phpunit/Framework/TestSuite.php:761
PHP   7. PHPUnit\Framework\TestSuite->run() phar:///Users/am/Sites/phpunit/phpunit/Framework/TestSuite.php:761
PHP   8. GeneratorTest->run() phar:///Users/am/Sites/phpunit/phpunit/Framework/TestSuite.php:761
PHP   9. PHPUnit\Framework\TestResult->run() phar:///Users/am/Sites/phpunit/phpunit/Framework/TestCase.php:808
PHP  10. GeneratorTest->runBare() phar:///Users/am/Sites/phpunit/phpunit/Framework/TestResult.php:685
PHP  11. GeneratorTest->runTest() phar:///Users/am/Sites/phpunit/phpunit/Framework/TestCase.php:854
PHP  12. GeneratorTest->testMockingOfThrowable() phar:///Users/am/Sites/phpunit/phpunit/Framework/TestCase.php:1172
PHP  13. PHPUnit\Framework\MockObject\Generator->getMock() /Users/am/Sites/sebastianbergmann/phpunit/tests/unit/Framework/MockObject/GeneratorTest.php:190
PHP  14. PHPUnit\Framework\MockObject\Generator->getObject() phar:///Users/am/Sites/phpunit/phpunit/Framework/MockObject/Generator.php:196
PHP  15. PHPUnit\Framework\MockObject\Generator->evalClass() phar:///Users/am/Sites/phpunit/phpunit/Framework/MockObject/Generator.php:562
PHP  16. eval() phar:///Users/am/Sites/phpunit/phpunit/Framework/MockObject/Generator.php:608

Fatal error: Class Mock_Exception_19a384fc contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (ExceptionWithThrowable::getAdditionalInformation) in phar:///Users/am/Sites/phpunit/phpunit/Framework/MockObject/Generator.php(608) : eval()'d code on line 1

Call Stack:
    0.0057     543992   1. {main}() /Users/am/Sites/phpunit:0
    0.1437    9827856   2. PHPUnit\TextUI\Command::main() /Users/am/Sites/phpunit:619
    0.1437    9827968   3. PHPUnit\TextUI\Command->run() phar:///Users/am/Sites/phpunit/phpunit/TextUI/Command.php:163
    0.4764   23119992   4. PHPUnit\TextUI\TestRunner->doRun() phar:///Users/am/Sites/phpunit/phpunit/TextUI/Command.php:207
    0.7250   23869248   5. PHPUnit\Framework\TestSuite->run() phar:///Users/am/Sites/phpunit/phpunit/TextUI/TestRunner.php:601
    0.7466   23869440   6. PHPUnit\Framework\TestSuite->run() phar:///Users/am/Sites/phpunit/phpunit/Framework/TestSuite.php:761
    3.7839   25022328   7. PHPUnit\Framework\TestSuite->run() phar:///Users/am/Sites/phpunit/phpunit/Framework/TestSuite.php:761
    3.8201   25324600   8. GeneratorTest->run() phar:///Users/am/Sites/phpunit/phpunit/Framework/TestSuite.php:761
    3.8201   25324600   9. PHPUnit\Framework\TestResult->run() phar:///Users/am/Sites/phpunit/phpunit/Framework/TestCase.php:808
    3.8202   25324600  10. GeneratorTest->runBare() phar:///Users/am/Sites/phpunit/phpunit/Framework/TestResult.php:685
    3.8204   25341232  11. GeneratorTest->runTest() phar:///Users/am/Sites/phpunit/phpunit/Framework/TestCase.php:854
    3.8204   25341288  12. GeneratorTest->testMockingOfThrowable() phar:///Users/am/Sites/phpunit/phpunit/Framework/TestCase.php:1172
    3.8204   25341288  13. PHPUnit\Framework\MockObject\Generator->getMock() /Users/am/Sites/sebastianbergmann/phpunit/tests/unit/Framework/MockObject/GeneratorTest.php:190
    3.8209   25344136  14. PHPUnit\Framework\MockObject\Generator->getObject() phar:///Users/am/Sites/phpunit/phpunit/Framework/MockObject/Generator.php:196
    3.8209   25344136  15. PHPUnit\Framework\MockObject\Generator->evalClass() phar:///Users/am/Sites/phpunit/phpunit/Framework/MockObject/Generator.php:562
    3.8211   25350656  16. eval('class Mock_Exception_19a384fc extends Exception implements ExceptionWithThrowable, PHPUnit\Framework\MockObject\MockObject
{
    private $__phpunit_invocationMocker;
    private $__phpunit_originalObject;
    private $__phpunit_configurable = [];
    private $__phpunit_returnValueGeneration = true;


    public function expects(\PHPUnit\Framework\MockObject\Matcher\Invocation $matcher): \PHPUnit\Framework\MockObject\Builder\InvocationMocker
    {
        return $this->__phpunit_getInvocationMocker()->expects($matcher);
    }

    public function method()
    {
        $any     = new \PHPUnit\Framework\MockObject\Matcher\AnyInvokedCount;
        $expects = $this->expects($any);

        return call_user_func_array([$expects, 'method'], func_get_args());
    }

    public function __phpunit_setOriginalObject($originalObject): void
    {
        $this->__phpunit_originalObject = $originalObject;
    }

    public function __phpunit_setReturnValueGeneration(bool $returnValueGeneration): void
    {
        $this->__phpunit_returnValueGeneration = $returnValueGeneration;
    }

    public function __phpunit_getInvocationMocker(): \PHPUnit\Framework\MockObject\InvocationMocker
    {
        if ($this->__phpunit_invocationMocker === null) {
            $this->__phpunit_invocationMocker = new \PHPUnit\Framework\MockObject\InvocationMocker($this->__phpunit_configurable, $this->__phpunit_returnValueGeneration);
        }

        return $this->__phpunit_invocationMocker;
    }

    public function __phpunit_hasMatchers(): bool
    {
        return $this->__phpunit_getInvocationMocker()->hasMatchers();
    }

    public function __phpunit_verify(bool $unsetInvocationMocker = true): void
    {
        $this->__phpunit_getInvocationMocker()->verify();

        if ($unsetInvocationMocker) {
            $this->__phpunit_invocationMocker = null;
        }
    }
}
') phar:///Users/am/Sites/phpunit/phpunit/Framework/MockObject/Generator.php:608


Process finished with exit code 255

Looks like we have some issues here because we are using a different version of phpunit/phpunit for testing the version of phpunit/phpunit we have currently checked out.

Path to phpunit.phar (with phpunit binary)

While not obvious, there’s a rather simple solution that was suggested by Nicolas Hohm: pick the Path to phpunit.phar option and specify the path the phpunit binary in the root of the project!

Path to phpunit.phar (with phpunit binary)

Running the tests by right-clicking on phpunit.xml, and selecting the option Run ‘phpunit.xml’ now works like a charm!

Even better, when enabling Xdebug and selecting the option Run ‘phpunit.xml’ with Coverage, we can now easily identify areas of the code base which are obviously lacking tests - something we have been doing yesterday and today here at FLYERALARAM, where the 5th PHPUnit Code Sprint has been taking place.

Hope it helps!