Skip to content

Wrong class autoloading and conflicts #2014

@soullivaneuh

Description

@soullivaneuh

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions