PHPUnit 在 MacOS Big Sur 上总是输出 "No tests executed!"

PHPUnit always output "No tests executed!" on MacOS Big Sur

尝试运行 任何 PHP单元测试时,我总是在Mac[上收到No tests executed!消息=101=]机器。在这台特定的机器上,一种简单的重现方法是安装 Laravel 的新实例并 运行 进行默认测试:

$ composer create-project --prefer-dist laravel/laravel blog
$ cd blog
$ vendor/bin/phpunit

=> No tests executed!

预期输出为 OK (2 tests, 2 assertions)

据我所知,这不是 PHP单元配置问题,因为默认的 Laravel 代码应该可以工作,其他框架和我尝试的任何代码都会出现同样的问题,不同的 PHPUnit 版本(8.5 和 9.4)和上面列出的确切步骤也会出现同样的问题 return Ubuntu VM 以及另一个 Mac 运行ning Catalina.

内的预期输出

实际上,我怀疑这不是 PHP单位问题,而是 MacOS 问题 一个 PHP 配置问题 ,稍后可能会在其他工具或项目中以其他形式出现。

PHP单元以前在这台机器上工作得很好,但它是一对夫妇weeks/months我没有真正使用过它。自从我上次(成功)在这个 Mac 上使用任何 PHPUnit 以来唯一改变的是升级到 MacOS Big Sur 并安装(然后卸载)Homebrew。

出现问题PHP单元找不到任何测试套件。 运行 vendor/bin/phpunit --testsuite Unit 仍然输出 No tests executed! 而在新的 Laravel 安装中,应该输出 Ok (1 test, 1 assertion).

所以我的问题是:在全新安装 macOS Big Sur 之前,还有什么我可以尝试解决这个问题的吗?有人遇到同样的问题吗?

编辑 - 2020 年 12 月 1 日

根据评论中的要求,这是我的 phpunit.xml,如上所述,the default Laravel one

<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         colors="true"
>
    <testsuites>
        <testsuite name="Unit">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>
        <testsuite name="Feature">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>
    </testsuites>
    <coverage processUncoveredFiles="true">
        <include>
            <directory suffix=".php">./app</directory>
        </include>
    </coverage>
    <php>
        <server name="APP_ENV" value="testing"/>
        <server name="BCRYPT_ROUNDS" value="4"/>
        <server name="CACHE_DRIVER" value="array"/>
        <!-- <server name="DB_CONNECTION" value="sqlite"/> -->
        <!-- <server name="DB_DATABASE" value=":memory:"/> -->
        <server name="MAIL_MAILER" value="array"/>
        <server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
        <server name="TELESCOPE_ENABLED" value="false"/>
    </php>
</phpunit>

同样,这应该无关紧要,因为任何配置return在这台计算机上的结果相同,甚至一些以前已知可以工作的结果,在其他计算机上Mac 和其他 OS.

运行 使用 artisan 进行测试:

$ php artisan test --testsuite Unit
  No tests executed! 

  Time:   0.01s

vendor/bin/phpunit --list-suites 的输出:

$ vendor/bin/phpunit --list-suites
PHPUnit 9.4.4 by Sebastian Bergmann and contributors.

Available test suite(s):
 - Unit
 - Feature

vendor/bin/phpunit -v --testsuite Unit 的输出:

$ vendor/bin/phpunit -v --testsuite Unit
PHPUnit 9.4.4 by Sebastian Bergmann and contributors.

Runtime:       PHP 7.3.22-(to be removed in future macOS)
Configuration: /Users/malou/Desktop/blog/phpunit.xml

No tests executed!

N.B.: /Users/malou/Desktop/blog/phpunit.xml is the one displayed above.

直接引用文件 有效 :

$ vendor/bin/phpunit ./tests/Unit
PHPUnit 9.4.4 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 00:00.006, Memory: 8.00 MB

OK (1 test, 1 assertion)

编辑 #2 - 2020 年 12 月 1 日

为您提供更多调试信息:

$ php -v
WARNING: PHP is not recommended\nPHP is included in macOS for compatibility with legacy software.\nFuture versions of macOS will not include PHP.
PHP 7.3.22-(to be removed in future macOS) (cli) (built: Oct 30 2020 00:19:11) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.22, Copyright (c) 1998-2018 Zend Technologies
    with Xdebug v2.7.0, Copyright (c) 2002-2019, by Derick Rethans

MacOS 大苏尔 11.0.1

编辑 - 2020 年 12 月 2 日

回应

我添加了以下内容:

    public static function main(bool $exit = true): int
    {
        var_dump(ini_get("auto_prepend_file"));
        var_dump($_SERVER['argv']); die;
        return (new static)->run($_SERVER['argv'], $exit);
    }

执行时vendor/bin/phpunit:

/Users/malou/Desktop/blog/vendor/phpunit/phpunit/src/TextUI/Command.php:163:
string(0) ""
/Users/malou/Desktop/blog/vendor/phpunit/phpunit/src/TextUI/Command.php:164:
array(1) {
  [0] =>
  string(18) "vendor/bin/phpunit"
}

执行时vendor/bin/phpunit --testsuite Unit

/Users/malou/Desktop/blog/vendor/phpunit/phpunit/src/TextUI/Command.php:163:
string(0) ""
/Users/malou/Desktop/blog/vendor/phpunit/phpunit/src/TextUI/Command.php:164:
array(3) {
  [0] =>
  string(18) "vendor/bin/phpunit"
  [1] =>
  string(11) "--testsuite"
  [2] =>
  string(4) "Unit"
}

tl;dr Apple 通过在大苏尔命名 PHP 7.3.22-(to be removed in future macOS) 打破了 version_compare。安装另一个版本的 PHP 可以解决这个问题。


我找到了问题的答案。这确实是一个 MacOS 问题,与 MacOS Big Sur 中 PHP 的内置版本有关。

经过相当多的调试(在另一个使用 PHPUnit 8 的项目上),我最终来到这里: https://github.com/sebastianbergmann/phpunit/blob/ccbf3962a948112056b0eded6e4c880af4ee3695/src/Util/Configuration.php#L1041-L1055

    private function satisfiesPhpVersion(DOMElement $node): bool
    {
        $phpVersion         = \PHP_VERSION;
        $phpVersionOperator = '>=';

        if ($node->hasAttribute('phpVersion')) {
            $phpVersion = (string) $node->getAttribute('phpVersion');
        }

        if ($node->hasAttribute('phpVersionOperator')) {
            $phpVersionOperator = (string) $node->getAttribute('phpVersionOperator');
        }

        return \version_compare(\PHP_VERSION, $phpVersion, (new VersionComparisonOperator($phpVersionOperator))->asString());
    }

当查看上面 PHP 单元代码的最后一行时(由于 $node->hasAttribute('phpVersion')$node->hasAttribute('phpVersionOperator') return 都是错误的),return 语句可以简化为:

version_compare(\PHP_VERSION, \PHP_VERSION, '>=')

现在,由于 MacOS 附带的 PHP 版本在 Big Sur 中被弃用,Apple 将该版本重命名为 7.3.22-(to be removed in future macOS)。这就是导致问题的原因,因为上面的代码现在变成了:

version_compare("7.3.22-(to be removed in future macOS)", "7.3.22-(to be removed in future macOS)", '>=')

其中 return false 而不是 true。

一个简单的测试方法:

$foo = version_compare("7.3.22-(to be removed in future macOS)", "7.3.22-(to be removed in future macOS)", '>=');
var_dump($foo); // bool(false)

$bar = version_compare("7.3.22", "7.3.22", '>=');
var_dump($bar); // bool(true)

这可能是因为,如 official PHP Documentation 中所述...

The function first replaces _, - and + with a dot . in the version strings and also inserts dots . before and after any non number so that for example '4.3.2RC1' becomes '4.3.2.RC.1'. Then it compares the parts starting from left to right. If a part contains special version strings these are handled in the following order: any string not found in this list < dev < alpha = a < beta = b < RC = rc < # < pl = p. This way not only versions with different levels like '4.1' and '4.1.2' can be compared but also any PHP specific version containing development state.

Note that pre-release versions, such as 5.3.0-dev, are considered lower than their final release counterparts (like 5.3.0).

...Apple 的命名方案可能 被视为不如自己的预发布版本,而不是等同于自己。

因此修复将覆盖 php 版本,据我所知这无法在全球范围内完成。使用 Homebrew 安装另一个版本的 PHP 似乎是最简单的解决方案