This issue is the continuing of #1757 as this is still here with PHPUnit 5.
Actually, php class are loaded first on PHPUnit library (composer or .phar) before project classes.
@Seldaek I take permission to ping you as I'm not really sure it's a PHPUnit or composer issue.
This can break tests if the used class is not the same between PHPUnit and project.
I'll elaborate with 3 concrete cases. First of all, here is my phpunit.xml project file:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
backupGlobals = "false"
backupStaticAttributes = "false"
colors = "true"
convertErrorsToExceptions = "true"
convertNoticesToExceptions = "true"
convertWarningsToExceptions = "true"
processIsolation = "false"
stopOnFailure = "false"
syntaxCheck = "false"
bootstrap = "app/autoload.php"
>
<php>
<server name="KERNEL_DIR" value="./app" />
</php>
<testsuites>
<testsuite name="Test Suite">
<directory>./tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./src</directory>
</whitelist>
</filter>
</phpunit>
$ ~/.composer/vendor/bin/phpunit
PHPUnit 5.1.3 by Sebastian Bergmann and contributors.
............................................................... 63 / 956 ( 6%)
............................................................... 126 / 956 ( 13%)
............................................................... 189 / 956 ( 19%)
............................................................... 252 / 956 ( 26%)
..PHP Fatal error: Declaration of GuzzleHttp\Client::send() must be compatible with GuzzleHttp\ClientInterface::send(GuzzleHttp\Message\RequestInterface $request) in /home/sullivan/projects/nexylan/project/vendor/guzzlehttp/guzzle/src/Client.php on line 26
PHP Stack trace:
PHP 1. {main}() /home/sullivan/.composer/vendor/phpunit/phpunit/phpunit:0
PHP 2. PHPUnit_TextUI_Command::main() /home/sullivan/.composer/vendor/phpunit/phpunit/phpunit:47
PHP 3. PHPUnit_TextUI_Command->run() /home/sullivan/.composer/vendor/phpunit/phpunit/src/TextUI/Command.php:106
PHP 4. PHPUnit_TextUI_TestRunner->doRun() /home/sullivan/.composer/vendor/phpunit/phpunit/src/TextUI/Command.php:155
PHP 5. PHPUnit_Framework_TestSuite->run() /home/sullivan/.composer/vendor/phpunit/phpunit/src/TextUI/TestRunner.php:429
PHP 6. PHPUnit_Framework_TestSuite->run() /home/sullivan/.composer/vendor/phpunit/phpunit/src/Framework/TestSuite.php:747
PHP 7. PHPUnit_Framework_TestSuite->run() /home/sullivan/.composer/vendor/phpunit/phpunit/src/Framework/TestSuite.php:747
PHP 8. PHPUnit_Framework_TestCase->run() /home/sullivan/.composer/vendor/phpunit/phpunit/src/Framework/TestSuite.php:747
PHP 9. PHPUnit_Framework_TestResult->run() /home/sullivan/.composer/vendor/phpunit/phpunit/src/Framework/TestCase.php:726
PHP 10. PHPUnit_Framework_TestCase->runBare() /home/sullivan/.composer/vendor/phpunit/phpunit/src/Framework/TestResult.php:685
PHP 11. PHPUnit_Framework_TestCase->runTest() /home/sullivan/.composer/vendor/phpunit/phpunit/src/Framework/TestCase.php:770
PHP 12. ReflectionMethod->invokeArgs() /home/sullivan/.composer/vendor/phpunit/phpunit/src/Framework/TestCase.php:910
PHP 13. Tests\ServiceAvailabilityTest->testServiceInstance() /home/sullivan/.composer/vendor/phpunit/phpunit/src/Framework/TestCase.php:910
PHP 14. Symfony\Component\DependencyInjection\Container->get() /home/sullivan/projects/nexylan/project/tests/ServiceAvailabilityTest.php:41
PHP 15. appTestDebugProjectContainer->getApiClient_NagiosService() /home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Container.php:312
PHP 16. AppBundle\ApiClient\NagiosApiClient->__construct() /home/sullivan/projects/nexylan/project/app/cache/test/appTestDebugProjectContainer.php:3223
PHP 17. AppBundle\ApiClient\ApiClient->initClient() /home/sullivan/projects/nexylan/project/src/AppBundle/ApiClient/NagiosApiClient.php:29
PHP 18. spl_autoload_call() /home/sullivan/projects/nexylan/project/src/AppBundle/ApiClient/NagiosApiClient.php:28
PHP 19. Composer\Autoload\ClassLoader->loadClass() /home/sullivan/projects/nexylan/project/src/AppBundle/ApiClient/NagiosApiClient.php:28
PHP 20. Composer\Autoload\includeFile() /home/sullivan/.composer/vendor/composer/ClassLoader.php:301
PHP 21. include() /home/sullivan/.composer/vendor/composer/ClassLoader.php:412
As you can see in the stack trace, the error occurred on the global vendor classes.
This error is "logic" because guzzle version differs between global and project vendors:
$ composer info -i | grep guzzle
guzzlehttp/guzzle 6.1.1 Guzzle is a PHP HTTP client library
guzzlehttp/promises 1.0.3 Guzzle promises library
guzzlehttp/psr7 1.2.1 PSR-7 message implementation
$ composer global info -i | grep guzzle
Changed current directory to /home/sullivan/.composer
guzzle/guzzle v3.9.3 PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle
guzzlehttp/guzzle 4.2.3 Guzzle is a PHP HTTP client library and framework for building RESTful web service clients
guzzlehttp/progress-subscriber 1.1.0 Emits upload and download progress events
guzzlehttp/streams 2.1.0 Provides a simple abstraction over streams of data (Guzzle 4+)
$ ./phpunit.phar
PHPUnit 5.1.3 by Sebastian Bergmann and contributors.
............................................................... 63 / 956 ( 6%)
............................................................... 126 / 956 ( 13%)
............................................................... 189 / 956 ( 19%)
............................................................... 252 / 956 ( 26%)
............................................................... 315 / 956 ( 32%)
............................................................... 378 / 956 ( 39%)
............................................................... 441 / 956 ( 46%)
............................................................... 504 / 956 ( 52%)
............................................................... 567 / 956 ( 59%)
............................................................... 630 / 956 ( 65%)
............................................................... 693 / 956 ( 72%)
............................................................... 756 / 956 ( 79%)
............................................................... 819 / 956 ( 85%)
............................................................... 882 / 956 ( 92%)
.................................E............................. 945 / 956 ( 98%)
........... 956 / 956 (100%)
Time: 13 seconds, Memory: 193.50Mb
There was 1 error:
1) Tests\ServiceAvailabilityTest::testServiceInstance with data set #733 ('web_profiler.controller.router')
Symfony\Component\Config\Exception\FileLoaderLoadException: The reserved indicator "@" cannot start a plain scalar; you need to quote the scalar at line 3 (near "resource: @AppBundle/Controller/Api/UserController.php") in /home/sullivan/projects/nexylan/project/app/config/routing_rest.yml (which is being imported from "/home/sullivan/projects/nexylan/project/app/config/routing.yml").
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Component/Config/Loader/FileLoader.php:130
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Component/Routing/Loader/YamlFileLoader.php:174
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Component/Routing/Loader/YamlFileLoader.php:94
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Component/Config/Loader/FileLoader.php:112
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Component/Routing/Loader/YamlFileLoader.php:174
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Component/Routing/Loader/YamlFileLoader.php:94
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Component/Config/Loader/DelegatingLoader.php:45
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php:83
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php:54
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php:39
/home/sullivan/projects/nexylan/project/app/cache/test/appTestDebugProjectContainer.php:12735
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Container.php:312
/home/sullivan/projects/nexylan/project/tests/ServiceAvailabilityTest.php:41
Caused by
Symfony\Component\Yaml\Exception\ParseException: The reserved indicator "@" cannot start a plain scalar; you need to quote the scalar at line 3 (near "resource: @AppBundle/Controller/Api/UserController.php").
/home/sullivan/projects/nexylan/project/vendor/friendsofsymfony/rest-bundle/FOS/RestBundle/Routing/Loader/RestYamlCollectionLoader.php:63
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Component/Config/Loader/FileLoader.php:112
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Component/Routing/Loader/YamlFileLoader.php:174
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Component/Routing/Loader/YamlFileLoader.php:94
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Component/Config/Loader/FileLoader.php:112
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Component/Routing/Loader/YamlFileLoader.php:174
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Component/Routing/Loader/YamlFileLoader.php:94
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Component/Config/Loader/DelegatingLoader.php:45
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php:83
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php:54
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php:39
/home/sullivan/projects/nexylan/project/app/cache/test/appTestDebugProjectContainer.php:12735
/home/sullivan/projects/nexylan/project/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Container.php:312
/home/sullivan/projects/nexylan/project/tests/ServiceAvailabilityTest.php:41
This exception should not be thrown because my project is running under Symfony 2.8 full stack.
But PHPUnit 5 use symfony/yaml component that is bumped to 3.0 version.
If I require phpunit directly on my project and run it:
$ ./bin/phpunit
PHPUnit 5.1.3 by Sebastian Bergmann and contributors.
............................................................... 63 / 956 ( 6%)
............................................................... 126 / 956 ( 13%)
............................................................... 189 / 956 ( 19%)
............................................................... 252 / 956 ( 26%)
............................................................... 315 / 956 ( 32%)
............................................................... 378 / 956 ( 39%)
............................................................... 441 / 956 ( 46%)
............................................................... 504 / 956 ( 52%)
............................................................... 567 / 956 ( 59%)
............................................................... 630 / 956 ( 65%)
............................................................... 693 / 956 ( 72%)
............................................................... 756 / 956 ( 79%)
............................................................... 819 / 956 ( 85%)
............................................................... 882 / 956 ( 92%)
............................................................... 945 / 956 ( 98%)
........... 956 / 956 (100%)
Time: 10.88 seconds, Memory: 183.50Mb
OK (956 tests, 321 assertions)
It works. But this is a workaround, not the solution. AFAIK, PHPUnit should be able to run standalone, at least with the .phar.
This isn't really a composer issue, and there is nothing we can do about it. The solution for phpunit might come with https://github.com/webmozart/php-scoper - in the meantime requiring it in your project is the best way, and I'd anyway argue it's the best way as it's the only way to guarantee you get the right phpunit version for every project.
Thanks for answering.
in the meantime requiring it in your project is the best way, and I'd anyway argue it's the best way as it's the only way to guarantee you get the right phpunit version for every project.
Well, adding PHPUnit with all dependencies on each project is quite painful IMO but yes, there is many way to do.
Anyway, PHPUnit can be installed on system wide (even if via apt-get) and I think this should work on standalone process.
This isn't really a composer issue, and there is nothing we can do about it. The solution for phpunit might come with https://github.com/webmozart/php-scoper
If I understand well this tools, this should be added on PHPUnit project to generate a unique namespace for the .phar of composer global install, right?
Right.
Sorry but why closing this issue?
If PHP-scoper is the solution, we should wait to implement it before closing.
As a workaround, @sebastianbergmann might want to bundle the release of Symfony\Component\Yaml\Yaml that comes with Symfony 2.8 instead of 3.0. Symfony >= 3.0 has "deprecated" functionality removed, thus breaking backwards compatibility. Not a great idea for a testing framework which is used for refactoring old applications, right? ;)
This issue is affecting me too, I can't really understand why.
Running the phpunit binary on my project folder don't work. Running it from vendor/bin runs fine.
php-scoper has now stable released. Could this be reconsidered?
EDIT: Only vendor should be prefixed, not PHPUnit classes to avoid confusion on IDE completion for example.
Most helpful comment
This issue is affecting me too, I can't really understand why.
Running the phpunit binary on my project folder don't work. Running it from
vendor/binruns fine.