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

Compatibility with PHPUnit 8+ #4366

Open
marcovtwout opened this issue May 28, 2021 · 17 comments
Open

Compatibility with PHPUnit 8+ #4366

marcovtwout opened this issue May 28, 2021 · 17 comments

Comments

@marcovtwout
Copy link
Member

marcovtwout commented May 28, 2021

Since PHPUnit 8 PHPUnit\Framework\TestCase::setUp() has a void return type added: https://phpunit.de/announcements/phpunit-8.html

This method is extended by CDbTestCase and CWebTestCase:
https://github.com/yiisoft/yii/blob/master/framework/test/CDbTestCase.php#L114
https://github.com/yiisoft/yii/blob/master/framework/test/CDbTestCase.php

Running tests on PHP7.0+ PHPUnit 8+ throws a fatal error:

PHP Fatal error:  Declaration of CDbTestCase::setUp() must be compatible with PHPUnit\Framework\TestCase::setUp(): void in (..)

On PHP 7.x you can stay on PHPUnit version 7 as a workaround.
However PHP 8 requires a minimum of PHPUnit version 8.

The most straightforward fix is to add the void return type to CDbTestCase and CWebTestCase, but this breaks backward compatibility with PHP < 7.1 and PHPUnit < 8.

Any ideas on how to patch this in a straightforward but backward compatible manner?

@samdark
Copy link
Member

samdark commented May 28, 2021

We are running tests with older PHPUnit, patched version: https://github.com/yiisoft/yii/blob/master/composer.json#L101 PHP 8 is already checked and pass: https://github.com/yiisoft/yii/runs/2676270735

@marcovtwout
Copy link
Member Author

Keeping PHPUnit 4 is acceptable for running framework unit tests, but for user projects I think it's better to support newer PHPUnit versions if possible. For example, anyone using Codeception with PHP 8 cannot stay on PHPUnit 4 and must upgrade to a much more recent version.

Backward compatibility is not as bad as I originally thought: adding void is backward compatible with older PHPUnit Versions. So the only BC break is with PHP 7.0 or below (EOL 01-2019). And this should not break production code as these two classes are only used in tests.

I think in this case supporting the newer versions might outweigh the BC break. What do you think?

@samdark
Copy link
Member

samdark commented May 31, 2021

And this should not break production code as these two classes are only used in tests.

Well, it is likely that it will affect someone's tests.

I think in this case supporting the newer versions might outweigh the BC break. What do you think?

It could be done with autoload map that is PHP-version specific instead.

@rob006
Copy link
Contributor

rob006 commented May 31, 2021

W could use different name (namespaced maybe?) for new base classes for tests. Reusing the same FQCL for different implementations will confuse SCA tools and will create problems if someone is not using Yii autoloader.

@marcovtwout
Copy link
Member Author

marcovtwout commented May 31, 2021

On a related note, running tests on PHPUnit 6+ also triggers an error where legacy autoloading code is performed when "PHPUnit_Runner_Version" doesn't exist.
https://github.com/yiisoft/yii/blob/master/framework/test/CTestCase.php#L11

That if-statement should probably read:
if(!class_exists('PHPUnit_Runner_Version') && !class_exists('PHPUnit\Runner\Version')) {

(I didn't notice this earlier since one of my common project dependencies already applied a workaround similar to https://github.com/yiisoft/yii/blob/master/tests/compatibility.php#L16-L19)

@marcovtwout
Copy link
Member Author

If anyone is looking for a quick workaround, here's what I'm using in a patch file for the time being:

// Compatibility fix for CTestCase and PHPUnit 7+
if (!class_exists('PHPUnit_Runner_Version') && class_exists('PHPUnit\Runner\Version')) {
    class_alias('\PHPUnit\Runner\Version', 'PHPUnit_Runner_Version');
}

// Compatibility fix for CTestCase and PHPUnit 8+
// @see https://github.com/yiisoft/yii/issues/4366
$yiiFiles = [
    __DIR__ . '/vendor/yiisoft/yii/framework/test/CDbTestCase.php',
    __DIR__ . '/vendor/yiisoft/yii/framework/test/CWebTestCase.php',
];
foreach($yiiFiles as $file) {
    if (file_exists($file)) {
        file_put_contents($file, str_replace(
            "protected function setUp()",
            "protected function\n\tsetUp(): void",
            file_get_contents($file)
        ));
    }
}

@marcovtwout
Copy link
Member Author

marcovtwout commented Jun 2, 2021

Some thoughts about the possible alternative solutions:

  1. We could define a second set of classes:
    • They could use the same name and need overrides in $classMap (https://github.com/yiisoft/yii/blob/master/framework/YiiBase.php#L68). But having duplicate classes will probably hinder IDE autocompletion and other problems @rob006 describes
    • They could be in a separate namespace. That would require some changes in core code (calls to Yii::import('system.test.*'); in yiit.php and in framework/test/) and users will have to update their code to extend the new base classes.
    • In both cases we have duplicate code (and documentation) which doesn't feel very nice.
  2. Alternatives with class_alias or dynamically generating code will have the same problems as above under nr 1.
  3. Code could be patched like in the workaround above, but not all user situations will support writing to framework folder and IDE will still throw warnings.

Comparing pros and cons, I think the best way forward is to add : void to the base classes. Yes it will break BC for users running PHP 7.0 or below, but only when running tests. And it requires the least amount of changes for those users that keep PHP up to date.

This is not an easy issue to decide on so I suggest to keep it open for now to gather some more community response.

@cebe
Copy link
Member

cebe commented Jun 23, 2021

@marcovtwout your patch could be applied by a composer plugin running on composer install which checks which version of phpunit is installed...

@Justinas-Jurciukonis
Copy link

@marcovtwout Any updates when Yii will support 8.1? Or even 8.2?

@marcovtwout
Copy link
Member Author

8.1 support is available in master, see https://github.com/yiisoft/yii/blob/master/CHANGELOG#L7

@yiisoft yiisoft deleted a comment from juslintek Sep 30, 2022
@johnrembo
Copy link

a little addition to @marcovtwout answer

if (!class_exists('PHPUnit_Framework_TestCase') && class_exists('PHPUnit\Framework\TestCase')) {
    class_alias('\PHPUnit\Framework\TestCase', 'PHPUnit_Framework_TestCase');
}

@marcovtwout
Copy link
Member Author

A few relevant updates about extended support and keeping things backward compatible:

@juslintek
Copy link

I will not state anything, but in my opinion Yii 1.1 projects that might be concerned with this change do not use composerised setup and probably will not upgrade anyway or they are like dead projects until their OS or yii projects will get hacked and they will begin to concern themselves with problems that they are facing and then start upgrading.

I think that best thing here would be to add void and create ruleset for tool like rectorphp to make conversion for legacy code if does not already and do the change. And write a blog post about it on how to migrate tests to latest version or composer upgrade could automatically trigger some script which would do that transformation for people concerned and having legacy code.

@marcovtwout
Copy link
Member Author

This issue has been open for a while, seems like a good time to revisit our stance. I would still propose to apply the solution suggested in #4366 (comment) which raises the minimum PHP version to 7.0 for those running unit tests.

@terabytesoftw
Copy link
Member

I would suggest upgrading to PHP 7.3, so it could support PHP 8.4 and PHPUnit 9.6.

@marcovtwout
Copy link
Member Author

@terabytesoftw What changes exactly are needed in yii framework code to support PHPUnit 9.6?

@terabytesoftw
Copy link
Member

@terabytesoftw What changes exactly are needed in yii framework code to support PHPUnit 9.6?

Well, basically it is eliminating the depreciated methods with the new methods, and eliminating the patches, it is not complicated.

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

No branches or pull requests

8 participants