Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong class autoloading and conflicts #2014

Closed
soullivaneuh opened this issue Dec 22, 2015 · 8 comments
Closed

Wrong class autoloading and conflicts #2014

soullivaneuh opened this issue Dec 22, 2015 · 8 comments

Comments

@soullivaneuh
Copy link

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>

With composer loaded PHPUnit binary

$ ~/.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+)

With phpunit.phar

$ ./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.

PHPUnit as a project dev dependency

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.

@Seldaek
Copy link
Contributor

Seldaek commented Dec 22, 2015

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.

@soullivaneuh
Copy link
Author

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?

@sebastianbergmann
Copy link
Owner

Right.

@soullivaneuh
Copy link
Author

Sorry but why closing this issue?

If PHP-scoper is the solution, we should wait to implement it before closing.

@lastzero
Copy link
Contributor

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? ;)

@iget-master
Copy link

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.

@soullivaneuh
Copy link
Author

soullivaneuh commented Jan 30, 2018

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.

@sebastianbergmann
Copy link
Owner

#2015 won't be implemented in time for PHPUnit 7.0. I am hoping for PHPUnit 7.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants