adriansuter/php-autoload-override

在您的类方法中覆盖全局作用域的完全限定函数调用,以便在测试期间对其进行模拟。

1.4 2022-11-09 08:46 UTC

This package is auto-updated.

Last update: 2024-09-09 12:40:46 UTC


README

Build Status Coverage Status Total Downloads License

此库允许覆盖类方法内的完全限定函数调用,以便在测试期间对其进行模拟。

注意:该库也可以用于其他场景,但我们建议仅用于测试目的。

PHP-Autoload-Override 网站主页

要求

  • PHP 7.3 或更高版本
  • Composer with PSR-4(不支持 PSR-0)

安装

$ composer require --dev adriansuter/php-autoload-override 1.0

PHPUnit 一起使用

假设我们要对以下类进行单元测试 Probability

namespace My\App;

class Probability
{
    public function pick(int $probability, string $color1, string $color2): string
    {
        if (\rand(1, 100) <= $probability) {
            return $color1;
        } else {
            return $color2;
        }
    }
}

该类有一个名为 pick 的方法,该方法接收一个概率(介于 0 和 100 之间)和两个颜色名称作为参数。然后该方法将使用全局作用域中的 rand 函数生成一个随机数,如果生成的数字小于等于给定的概率,则该方法将返回第一个颜色,否则将返回第二个颜色。

问题

由于我们无法控制 rand 函数的输出(它位于全局作用域中),因此我们无法对该方法进行单元测试。嗯,直到现在。使用 PHP-Autoload-Override 库,可以覆盖 rand 函数并因此控制其生成的随机数。

解决方案

安装 PHP-Autoload-Override 库后,我们打开测试套件的引导脚本(另请参阅 PHPUnit 配置)。在那里我们将编写以下代码

// tests/bootstrap.php

/** @var \Composer\Autoload\ClassLoader $classLoader */
$classLoader = require_once __DIR__ . '/../vendor/autoload.php';

\AdrianSuter\Autoload\Override\Override::apply($classLoader, [
    \My\App\Probability::class => [
        'rand' => function ($min, $max): int {
            if (isset($GLOBALS['rand_return'])) {
                return $GLOBALS['rand_return'];
            }

            return \rand($min, $max);
        }
    ]
]);

现在,类 Probability 将被加载到 PHPUnit 运行时中,使得类 Probability 中对全局作用域中的 rand() 函数的所有函数调用都由上面的闭包覆盖。

我们的测试类现在可以写成如下所示。

namespace My\App\Tests;

use My\App\Probability;
use PHPUnit\Framework\TestCase;

final class ProbabilityTest extends TestCase
{
    protected function tearDown()
    {
        if (isset($GLOBALS['rand_return'])) {
            unset($GLOBALS['rand_return']);
        }
    }

    public function testPick()
    {
        $p = new Probability();

        $GLOBALS['rand_return'] = 35;

        $this->assertEquals('blue', $p->pick(34, 'red', 'blue'));
        $this->assertEquals('red', $p->pick(35, 'red', 'blue'));
    }
}

测试用例 testPick 会调用两次 pick 方法。由于我们覆盖了 \rand 函数,我们可以控制其返回值始终为 35。因此,第一次调用检查 else 块是否执行。第二次调用检查 if 块是否执行。太好了,100% 代码覆盖率。

请注意,此覆盖仅在单元测试期间应用。

了解更多信息

许可证

PHP-Autoload-Override 库采用 MIT 许可证授权。有关更多信息,请参阅 许可证文件