Lzh on GitHub

PHPUnit 集成

Mockery 被设计为一个易于使用的 独立 模拟对象框架,因此它与任何测试框架的集成完全是可选的。要集成 Mockery,我们需要为测试定义一个 tearDown() 方法,其中包含以下内容(我们可以使用更短的 \Mockery 命名空间别名):

Mockery 被设计为一个易于使用的 独立 模拟对象框架,因此它与任何测试框架的集成完全是可选的。要集成 Mockery,我们需要为测试定义一个 tearDown() 方法,其中包含以下内容(我们可以使用更短的 \Mockery 命名空间别名):

public function tearDown() {
    \Mockery::close();
}

这个静态调用会清理当前测试使用的 Mockery 容器,并运行为我们的期望所需的任何验证任务。

为了在使用 Mockery 时更简洁,我们还可以显式地使用 Mockery 命名空间并使用一个更短的别名。例如:

use \Mockery as m;

class SimpleTest extends \PHPUnit\Framework\TestCase
{
    public function testSimpleMock()
    {
        $mock = m::mock('simplemock');
        $mock->shouldReceive('foo')->with(5, m::any())->once()->andReturn(10);

        $this->assertEquals(10, $mock->foo(5));
    }

    public function tearDown()
    {
        m::close();
    }
}

Mockery 附带了一个自动加载器,因此我们不需要在测试中散布 require_once() 调用。要使用它,请确保 Mockery 在我们的 include_path 中,并将以下内容添加到我们的测试套件的 Bootstrap.phpTestHelper.php 文件中:

require_once 'Mockery/Loader.php';
require_once 'Hamcrest/Hamcrest.php';

$loader = new \Mockery\Loader;
$loader->register();

如果我们使用 Composer,我们可以将其简化为包含 Composer 生成的自动加载文件:

require __DIR__ . '/../vendor/autoload.php'; // 假设 vendor 在上一级目录
在 Hamcrest 1.0.0 之前,Hamcrest.php 文件名有一个小写 “h”(即 hamcrest.php)。如果将 Hamcrest 升级到 1.0.0,请记住检查所有项目的文件名是否已更新。

要将 Mockery 集成到 PHPUnit 中并避免必须调用 close 方法,以及让 Mockery 将自己从代码覆盖率报告中移除,请让您的测试用例扩展 \Mockery\Adapter\Phpunit\MockeryTestCase

class MyTest extends \Mockery\Adapter\Phpunit\MockeryTestCase
{
}

另一种方法是使用提供的 trait

class MyTest extends \PHPUnit\Framework\TestCase
{
    use \Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
}

扩展 MockeryTestCase 或使用 MockeryPHPUnitIntegration trait 是 推荐的 将 Mockery 与 PHPUnit 集成的方式,自 Mockery 1.0.0 以来。

PHPUnit 监听器

在 1.0.0 版本之前,Mockery 提供了一个 PHPUnit 监听器,它会在测试结束时为我们调用 Mockery::close()。自 1.0.0 版本以来,这发生了重大变化。

现在,Mockery 提供了一个 PHPUnit 监听器,如果 Mockery::close() 没有被调用,它会使测试失败。它可以帮助识别我们忘记包含 trait 或扩展 MockeryTestCase 的测试。

如果我们使用 PHPUnit 的 XML 配置方法,我们可以包含以下内容来加载 TestListener

<listeners>
    <listener class="\Mockery\Adapter\Phpunit\TestListener"></listener>
</listeners>

请确保 Composer 或 Mockery 的自动加载器存在于引导文件中,否则我们还需要定义一个指向 TestListener 类文件的 “file” 属性。

如果我们以编程方式创建测试套件,我们可以像这样添加监听器:

// 创建套件。
$suite = new PHPUnit\Framework\TestSuite();

// 创建监听器并将其添加到套件中。
$result = new PHPUnit\Framework\TestResult();
$result->addListener(new \Mockery\Adapter\Phpunit\TestListener());

// 运行测试。
$suite->run($result);
PHPUnit 提供了一项功能,允许 测试在单独的进程中运行,以确保更好的隔离。Mockery 使用 Mockery::close() 方法验证模拟的期望,并提供一个 PHPUnit 监听器,它会在每次测试后自动为我们调用此方法。

然而,当使用 PHPUnit 的进程隔离时,此监听器不会在正确的进程中被调用,导致期望可能得不到满足,但不会引发任何 Mockery\Exception。为了避免这种情况,我们不能依赖提供的 Mockery PHPUnit TestListener,并且我们需要显式地调用 Mockery::close。最简单的解决方案是像前面解释的那样,将此调用包含在 tearDown() 方法中。