PHPUnit在MacOS Big Sur上始终输出“未执行测试!”

11

在我的MacOS机器上,尝试运行 任何 PHPUnit 测试时,我总是会得到一个 No tests executed! 的消息。在这台特定的机器上,重现的简单方法是安装 Laravel 的新实例并运行默认测试:

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

=> No tests executed!

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

据我所知,这不是PHPUnit配置问题,因为预计默认的Laravel代码可以工作,使用其他框架和任何我尝试的代码都会出现相同的问题,不同的PHPUnit版本(8.5和9.4)存在相同的问题,并且上述确切步骤在Ubuntu VM中以及运行Catalina的另一台Mac上返回预期的输出。

实际上,我怀疑这不是PHPUnit问题,而更像是MacOS问题PHP配置问题,可能会在将来的其他工具或项目中表现出其他形式。

PHPUnit以前在这台机器上运行良好,但是已经有几周/几个月我没有真正使用它了。自从我上次(成功地)在此Mac上使用PHPUnit以来唯一改变的事情就是升级到了macOS Big Sur并安装(然后卸载)Homebrew。

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

因此,我的问题是:在重新安装macOS Big Sur之前,我还能尝试什么来解决这个问题,是否有人遇到相同的问题?

编辑- 2020年12月1日

根据评论中的要求,这里是我的phpunit.xml,正如上面所述,这是默认的Laravel配置文件

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

同样的,这并不重要,因为任何配置在这台电脑上返回相同的结果,甚至一些先前在其他Mac和其他操作系统上运行良好的配置也是如此。

使用 artisan 运行测试:

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

  Time:   0.01s
< p >运行命令 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 Big Sur 11.0.1

Edit - Dec 2nd 2020

In response to PHPUnit always output "No tests executed!" on MacOS Big Sur:

I added the following:

    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"
}

1
vendor/bin/phpunit --list-suites 输出什么?而 vendor/bin/phpunit -v --testsuite Unit 配置文件是 phpunit.xml 吗? - Total Pusher
1
正如@TotalPusher所提到的,检查一下你的phpunit.xml文件。它们是否被正确定义了?最好在这里粘贴一下,这样我们就可以看一下。另外,我猜你已经按照预期完成了其他部分,比如在composer json中定义了你的测试命名空间,并从phpunit TestCase类继承了它们。 - Tuhin
@TotalPusher 请查看问题编辑中这些命令和phpunit.xml内容的结果。 - Louis Charette
1
好的,这是一个棘手的情况。在方法 PHPUnit\TextUI\Command::main(); 中我发现了这个:return (new static)->run($_SERVER['argv'], $exit);。请添加 var_dump(ini_get("auto_prepend_file")); var_dump($_SERVER['argv']); die; 并显示结果。 - Total Pusher
1
找到原因了。这是苹果的问题。我会在找到永久解决方案后给出答案。 - Louis Charette
显示剩余4条评论
1个回答

16

tl;dr 由于在Big Sur中将PHP命名为7.3.22-(to be removed in future macOS),导致Apple破坏了version_compare。安装另一个版本的PHP可以解决这个问题。


我找到了解决方案。这确实是一个与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());
    }

当看到上面 PHPUnit 代码的最后一行时(考虑到 $node->hasAttribute('phpVersion')$node->hasAttribute('phpVersionOperator') 都返回 false),return 语句可以简化为:

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

现在,由于随着Big Sur一起发货的PHP版本已经过时,苹果将该版本重命名为7.3.22-(将来在macOS中被删除)。 这就是问题所在,因为上面的代码现在变成了:

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

哪些会返回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)

这可能是因为,正如在 官方 PHP 文档 中解释的那样...

该函数首先将版本字符串中的 _、- 和 + 替换为点 .,并在任何非数字之前和之后插入点 .,以便例如 '4.3.2RC1' 变成 '4.3.2.RC.1'。然后从左到右比较各个部分。如果某个部分包含特殊版本字符串,则按照以下顺序处理:不在此列表中的任何字符串 < dev < alpha = a < beta = b < RC = rc < # < pl = p。这样就不仅可以比较不同级别的版本,如 '4.1' 和 '4.1.2',还可以比较包含开发状态的任何 PHP 特定版本。

请注意,预发布版本(例如 5.3.0-dev)被认为低于其最终发布版本对应物(例如 5.3.0)。

...苹果的命名方案 可能 被视为低于自身的预发布版本,而不是与自身相等。

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


2
哇,这是一个很好的发现。苹果这样破坏 PHP 真的很糟糕,他们本可以将其打包为维护版本。 - Tuhin
1
原来问题出在版本字符串末尾的右括号。当PHP规范化版本号时,会得到一个空的最终组件,而PHP的version_compare存在一个错误,即两个字符串都有一个空的最终组件时,比较结果是小于而不是等于。 - Anomie
苹果公司做出了多么荒谬的决定。 - nickdnk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接