Using codeception 2.4 with phpunit 7.1.5 and want to start the tests via console vendor/bin/codecept run
It breaks with a Fatal Error:
Compile Error: Declaration of Codeception\Test\Test::toString() must be compatible with PHPUnit\Framework\SelfDescribing::toString(): string
codeception 2.4 with phpunit < 7 (in my case phpunit 6.5.8) works as expected.
I don't have this issue with the same setup:
+ php vendor/bin/codecept run --html
Codeception PHP Testing Framework v2.4.2
Powered by PHPUnit 7.1.5 by Sebastian Bergmann and contributors.
Time: 1.55 minutes, Memory: 14.00MB
So I assume you have PHPUnit incompatible versions... Maybe you have PHPUnit wrapper 6.x and PHPUnit 7 or smth like that
@DavertMik I'm hitting the same issue. I actually commented on #4978 about it, but since this ticket's open, I'll re-post my output here:
Codeception PHP Testing Framework v2.4.2
Powered by PHPUnit 7.1.5 by Sebastian Bergmann and contributors.
PHP Fatal error: Declaration of Codeception\Test\Test::toString() must be compatible with PHPUnit\Framework\SelfDescribing::toString(): string in /vagrant/lib/vendor/codeception/codeception/src/Codeception/Test/Test.php on line 18
PHP Stack trace:
PHP 1. {main}() /vagrant/lib/vendor/codeception/codeception/codecept:0
PHP 2. Codeception\Application->run() /vagrant/lib/vendor/codeception/codeception/codecept:42
PHP 3. Codeception\Application->run() /vagrant/lib/vendor/codeception/codeception/src/Codeception/Application.php:108
PHP 4. Codeception\Application->doRun() /vagrant/lib/vendor/symfony/console/Application.php:122
PHP 5. Codeception\Application->doRunCommand() /vagrant/lib/vendor/symfony/console/Application.php:215
PHP 6. Codeception\Command\Run->run() /vagrant/lib/vendor/symfony/console/Application.php:858
PHP 7. Codeception\Command\Run->execute() /vagrant/lib/vendor/symfony/console/Command/Command.php:240
PHP 8. Codeception\Command\Run->runSuites() /vagrant/lib/vendor/codeception/codeception/src/Codeception/Command/Run.php:361
PHP 9. Codeception\Codecept->run() /vagrant/lib/vendor/codeception/codeception/src/Codeception/Command/Run.php:466
PHP 10. Codeception\Codecept->runSuite() /vagrant/lib/vendor/codeception/codeception/src/Codeception/Codecept.php:158
PHP 11. Codeception\SuiteManager->loadTests() /vagrant/lib/vendor/codeception/codeception/src/Codeception/Codecept.php:188
PHP 12. Codeception\Test\Loader->loadTests() /vagrant/lib/vendor/codeception/codeception/src/Codeception/SuiteManager.php:95
PHP 13. Codeception\Test\Loader\Cept->loadTests() /vagrant/lib/vendor/codeception/codeception/src/Codeception/Test/Loader.php:134
PHP 14. spl_autoload_call() /vagrant/lib/vendor/codeception/codeception/src/Codeception/Test/Loader/Cept.php:21
PHP 15. Composer\Autoload\ClassLoader->loadClass() /vagrant/lib/vendor/codeception/codeception/src/Codeception/Test/Loader/Cept.php:21
PHP 16. Composer\Autoload\includeFile() /vagrant/lib/vendor/composer/ClassLoader.php:322
PHP 17. include() /vagrant/lib/vendor/composer/ClassLoader.php:444
PHP 18. spl_autoload_call() /vagrant/lib/vendor/codeception/codeception/src/Codeception/Test/Cept.php:12
PHP 19. Composer\Autoload\ClassLoader->loadClass() /vagrant/lib/vendor/codeception/codeception/src/Codeception/Test/Cept.php:12
PHP 20. Composer\Autoload\includeFile() /vagrant/lib/vendor/composer/ClassLoader.php:322
PHP 21. include() /vagrant/lib/vendor/composer/ClassLoader.php:444
Here's a truncated output of my composer show, to prove I'm running the latest of Codeception and PHPUnit Wrapper:
...
codeception/codeception 2.4.2 BDD-style testing framework
codeception/phpunit-wrapper 7.1.3 PHPUnit classes used by Codeception
codeception/stub 2.0.1 Flexible Stub wrapper for PHPUnit's Mock Builder
...
phpunit/dbunit 4.0.0 PHPUnit extension for database interaction testing
phpunit/php-code-coverage 6.0.5 Library that provides collection, processing, and rendering functionality for PHP code coverage information.
phpunit/php-file-iterator 1.4.5 FilterIterator implementation that filters files based on a list of suffixes.
phpunit/php-text-template 1.2.1 Simple template engine.
phpunit/php-timer 2.0.0 Utility class for timing
phpunit/php-token-stream 3.0.0 Wrapper around PHP's tokenizer extension.
phpunit/phpunit 7.1.5 The PHP Unit Testing framework.
phpunit/phpunit-mock-objects 6.1.2 Mock Object library for PHPUnit
...
sebastian/code-unit-reverse-lookup 1.0.1 Looks up which function or method a line of code belongs to
sebastian/comparator 3.0.0 Provides the functionality to compare PHP values for equality
sebastian/diff 3.0.0 Diff implementation
sebastian/environment 3.1.0 Provides functionality to handle HHVM/PHP environments
sebastian/exporter 3.1.0 Provides the functionality to export PHP variables for visualization
sebastian/finder-facade 1.2.2 FinderFacade is a convenience wrapper for Symfony's Finder component.
sebastian/global-state 2.0.0 Snapshotting of global state
sebastian/object-enumerator 3.0.3 Traverses array structures and object graphs to enumerate all referenced objects
sebastian/object-reflector 1.1.1 Allows reflection of object attributes, including inherited and non-public ones
sebastian/phpcpd 4.0.0 Copy/Paste Detector (CPD) for PHP code.
sebastian/recursion-context 3.0.0 Provides functionality to recursively process PHP variables
sebastian/resource-operations 1.0.0 Provides a list of PHP built-in functions that operate on resources
sebastian/version 2.0.1 Library that helps with managing the version number of Git-hosted PHP projects
...
My only assumption that PHPUnit classes are loaded before Codeception classes...
Do you do some bootstrap?
@DavertMik There's nothing in the global bootstrap at all and nothing in my configs or helper classes explicitly references PHPUnit. However, in my require-dev, phpunit is included separately (and before codeception). Since it's erroring out during spl_autoload calls, could that possibly be the issue?
"require-dev": {
"phpunit/phpunit" : "^7.0",
"phpunit/dbunit" : ">=1.4",
"pdepend/pdepend" : "^2.0",
"phploc/phploc" : "*",
"phpmd/phpmd" : "^2.0",
"squizlabs/php_codesniffer" : "^3",
"sebastian/phpcpd" : "^4",
"codeception/codeception" : "2.*",
"robmorgan/phinx" : "^0.9",
"flow/jsonpath" : "0.3.*",
"mockery/mockery" : "dev-master",
"php-mock/php-mock-phpunit" : "^2",
"mikey179/vfsStream" : "~1",
"phpstan/phpstan" : "^0.9",
"roave/security-advisories" : "dev-master",
"facebook/webdriver" : "^1.5"
},
We currently have distinct unit and acceptance testing suites (with the unit tests using PHPUnit directly) so we can't easily throw out PHPUnit from our dev dependencies.
@DavertMik Any update on this by chance? I noticed some updates around 7.2 support, so I updated codeception/codeception to 2.4.5, phpunit/phpunit to 7.2.7, and codeception/phpunit-wrapper to 7.2.0, but I'm still hitting the same error.
If you need a more detailed proof of concept, let me know, and I'll take another look at what the most minimal repro steps are.
We have the same problem, because we also use zendframework/zend-test and they have an autoload file which requires a PHPUnit Class and than the phpunit7-interfaces.php does not overwrite the interfaces anymore.
When will Codeception be fully compatible with PHPUnit 7.x ?
When will Codeception be fully compatible with PHPUnit 7.x ?
My best guess is either June 2019 or June 2020, because we usually make a big release around that time of the year. I think that it is necessary to drop support for PhpUnit 6.x in order to be fully compatible with 7.x.
Also compatibility with PhpUnit 7.* is a moving goal post, PhpUnit introduced breaking changes (from our point of view) in 7.1.0, 7.1.5 and 7.2.0
@Naktibalda I'm not sure that support for PHPUnit 6 would need to be dropped, but support for PHP 5.6 would. The root issue here is that the override methods have less return type specificity than their parent methods. It is, however, acceptable for the override methods to have greater return type specificity, so the conflict shouldn't be with PHPUnit 6 except in the case of namespace conflicts. The more likely conflict would be with PHP 5.6 since it doesn't support return types.
To clarify, Codeception updating in June and PHPUnit updating in February would mean that there will be periods of time where Codeception may only fully work with unsupported versions of PHPUnit. Should that be the expectation for Codeception users going forward, at least for the moment? I'm not particularly worried about that, but mostly want to understand and set expectations on when my teams can expect to upgrade PHPUnit.
I'll leave this discussion to @DavertMik
Is dropping support for PHP 5.6 before December 2018 (when PHP drops support for it entirely) off-limits? If not, I might try to get a branch together to address this and then see what CI reports about it.
@DavertMik Looking into this again, could you explain how the phpunit-wrapper would have any influence in this explicit case? I'm having a hard time finding how anything around Test::toString is being wrapped in that library. There's this but that only seems to apply when the SelfDescribing interface doesn't exist.
@DavertMik
I have the same problem with;
The class Codeception\Test\Test is incompatible with the interface PHPUnit\FrameworkSelfDescribing . The abstract method toString() in the class Test has no return type
/**
* Returns a string representation of the object.
*/
public function toString(): string;
https://github.com/sebastianbergmann/phpunit/blob/7.5/src/Framework/SelfDescribing.php
https://github.com/sebastianbergmann/phpunit/blob/8.2/src/Framework/SelfDescribing.php
@DavertMik why does codeception 3.0 still support PHP 5.6?
Wasn't this the perfect chance to get a rid of the dependency?
Because otherwise it is not possible to use codeception with phpunit 7/8 and php >=7.1 or is there a other way?
Codeception 3 is compatible with PHPUnit 5, 6, 7 and 8.
I think the problem is that the phpunit-wapper only works if the PHPUnit\Framework\SelfDescribing is not loaded before Codeception\PHPUnit\Init::init() is executed.
My dependencies are:
Tests:
If I remove all dev dependencies except codeception from my project it works. Because the !interface_exists(SelfDescribing::class, false) return true.
If I only add phpunit and codeception to the dependency it also works. Because the !interface_exists(SelfDescribing::class, false) return true.
If I install phpunit, codeception and symfony/phpunit-bridge it also works. Because the !interface_exists(SelfDescribing::class, false) return true.
But if I install php-mock/php-mock-phpunit I got the error, because php-mock-phpunit also have an autoload-file which defines some class-aliases and when it calls the interface_exists(\PHPUnit\Framework\MockObject\Matcher\Invocation::class) function the autoloader kicks in and load the interface and it's parents interfaces in the ram.
So the !interface_exists(SelfDescribing::class, false) return false and the orignal interface is loaded.
So maybe you should add php-mock/php-mock-phpunit to the conflicts section in your composer.json
But this don't fix the loading issue.
It is good to know that Codeception isn't the only project struggling with PHPUnit compatibility.
maybe would be better release major versions like PHPUnit does and drop old unsupported PHP and PHPUnit versions. I believe that it is very hard to support so old and so many PHP and PHPUnit versions at the same time. Maybe would be easier to support Codeception 3.x and 4.x and drop support in a year or two or longer but only merge bugfixes or something.
So far nobody wants to support previous versions.
I would rather stop chasing new versions of PHPUnit.
@Naktibalda the problem is that if Codeception will not support the latest PHPUnit versions then it will be not possible to support latest PHP versions
I think this is a more generic compatibility issue between Codeception (v2.4 in this case but also v3 and 4) and PHP > 7.1 due to a bugfix that was introduced in PHP 7.2 .
Codeception works fine on any version of PHP up to 7.4, special combination of dependencies is required to reproduce this issue.
I reproduced this issue with zend-test and now I finally fully understand what's going on here.
@reinfi described it correctly back in 2018:
We have the same problem, because we also use zendframework/zend-test and they have an autoload file which requires a PHPUnit Class and than the phpunit7-interfaces.php does not overwrite the interfaces anymore.
Codeception's PHPUnit 7+ compatibility relies on rather ugly hack of defining interfaces first, so PHPUnit doesn't get chance to define them.
zend-test autoload file is loaded by composer first and it forces autoloading of PHPUnit\Framework\TestCase which loads all relevant interfaces.
phpunit-wrappers's phpunit7-interfaces.php file is included at a runtime later and can't define interfaces because they are already defined by PHPUnit.
To get ZF2 tests passing, @DavertMik created davert/replace-zend-test package.
I am working on a more reliable way to make Codeception\Test\Test class compatible with different versions of PHP.
I implemented more reliable abstraction of PHPUnit interfaces in
https://github.com/Codeception/Codeception/pull/5894 and https://github.com/Codeception/phpunit-wrapper/pull/77
Please test it by setting composer constraints to:
"codeception/codeception": "dev-abstract-test as 4.2.0",
"codeception/phpunit-wrapper": "dev-7.1-abstract-test as 7.9.99",
@Naktibalda I just tested this and the fix works (i can execute tests against PHPUnit7) Do you need more tests? We kind of need this feature for our migration to PHP 7.4.
@Naktibalda Not to pressure you but could you answer the above question?
@Naktibalda Any update on this issue?
This issue won't exist in Codeception 5.0 which drops support for old versions of PHPUnit: https://github.com/Codeception/Codeception/pull/6067
Most helpful comment
I think the problem is that the phpunit-wapper only works if the
PHPUnit\Framework\SelfDescribingis not loaded beforeCodeception\PHPUnit\Init::init()is executed.My dependencies are:
Tests:
If I remove all dev dependencies except codeception from my project it works. Because the
!interface_exists(SelfDescribing::class, false)return true.If I only add phpunit and codeception to the dependency it also works. Because the
!interface_exists(SelfDescribing::class, false)return true.If I install phpunit, codeception and symfony/phpunit-bridge it also works. Because the
!interface_exists(SelfDescribing::class, false)return true.But if I install php-mock/php-mock-phpunit I got the error, because php-mock-phpunit also have an autoload-file which defines some class-aliases and when it calls the
interface_exists(\PHPUnit\Framework\MockObject\Matcher\Invocation::class)function the autoloader kicks in and load the interface and it's parents interfaces in the ram.So the
!interface_exists(SelfDescribing::class, false)return false and the orignal interface is loaded.So maybe you should add php-mock/php-mock-phpunit to the conflicts section in your composer.json
But this don't fix the loading issue.