bilge/mockery

Mockery 是一个简单而灵活的 PHP 模拟对象框架

0.9.3 2014-12-22 10:06 UTC

README

Build Status Latest Stable Version Coverage Status Total Downloads

Mockery 是一个简单而灵活的 PHP 模拟对象框架,用于与 PHPUnit、PHPSpec 或任何其他测试框架一起进行单元测试。其核心目标是提供一个具有简洁 API 的测试双框架,该 API 能够使用可读的领域特定语言 (DSL) 清晰地定义所有可能的对象操作和交互。Mockery 被设计为一个可直接替代 PHPUnit 的 phpunit-mock-objects 库的方案,Mockery 与 PHPUnit 集成简单,并且可以与 phpunit-mock-objects 一起运行,而不会导致世界末日。

Mockery 采用新 BSD 许可证发布。

安装

要安装 Mockery,请运行以下命令,您将获得最新版本

composer require --dev mockery/mockery

⚠️️ 以下 README 的其余部分专门针对 master 分支(1.0-dev)。

文档

在旧版本中,此 README 文件是 Mockery 的文档。随着时间的推移,我们对其进行了改进,并为您创建了一份广泛的文档。请将此 README 文件作为 Mockery 的起点,但请阅读文档以了解如何使用 Mockery。

当前版本可在 docs.mockery.io 上查看。

测试双

测试双(通常称为模拟)模拟真实对象的行为。它们通常用于提供测试隔离、替代尚未存在的对象,或允许在不要求实际实现的情况下探索性设计类 API。

测试双框架的优点是允许灵活地生成和配置测试双。它们允许使用灵活的 API 设置预期的方法调用和/或返回值,该 API 能够以尽可能接近自然语言描述的方式捕获每个可能的真实对象行为。使用 Mockery::mock 方法创建测试双。

$double = Mockery::mock();

如果您需要 Mockery 创建一个测试双以满足特定的类型提示,您可以将该类型传递给 mock 方法。

class Book {}

interface BookRepository {
    function find($id): Book;
    function findAll(): array;
    function add(Book $book): void;
}

$double = Mockery::mock(BookRepository::class);

有关创建和使用测试双的详细说明,请参阅文档中的 创建测试双 部分。

方法存根 🎫

方法存根是一种使您的测试双对某些方法调用返回预定义响应的机制。使用存根,您不必关心该方法被调用的次数,甚至根本不调用。存根用于向待测系统提供间接输入。

$double->allows()->find(123)->andReturns(new Book());

$book = $double->find(123);

如果您之前使用过 Mockery,您可能在上面的示例中看到了一些新内容——我们使用 allows 创建了一个方法存根,而不是“旧”的 shouldReceive 语法。这是 Mockery v1 的一个新功能,但请放心,可靠的旧 shouldReceive 语法仍然存在。

对于 Mockery 的新用户,上面的示例也可以写成以下形式

$double->shouldReceive('find')->with(123)->andReturn(new Book());
$book = $double->find(123);

如果您的存根不需要特定的参数,您也可以使用此快捷方式一次设置多个调用

$double->allows([
    "findAll" => [new Book(), new Book()],
]);

或者

$double->shouldReceive('findAll')
    ->andReturn([new Book(), new Book()]);

您还可以使用此快捷方式,它创建一个双例并在一个调用中设置一些存根

$double = Mockery::mock(BookRepository::class, [
    "findAll" => [new Book(), new Book()],
]);

方法调用期望 📲

方法调用期望是一种允许您验证特定方法是否被调用的机制。您可以指定参数,也可以指定期望它被调用多少次。方法调用期望用于验证待测系统的间接输出。

$book = new Book();

$double = Mockery::mock(BookRepository::class);
$double->expects()->add($book);

在测试过程中,Mockery 会按照规定接受对 add 方法的调用。当你完成对测试系统的操作后,需要使用 Mockery::close 方法告诉 Mockery 检查该方法是否按预期调用。一种方法是将其添加到 PHPUnit 的 tearDown 方法中。

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

expects() 方法会自动设置一个期望,即方法调用(以及匹配的参数)只被调用一次。如果你期望有更多调用,可以选择更改此设置。

$double->expects()->add($book)->twice();

如果你之前使用过 Mockery,你可能会在上述示例中看到一些新内容——我们使用 expects 创建了一个方法期望,而不是“旧”的 shouldReceive 语法。这是 Mockery v1 的新特性,但就像前一部分中的 accepts 一样,它也可以用“旧”风格编写。

对于 Mockery 的新用户,上面的示例也可以写成以下形式

$double->shouldReceive('find')
    ->with(123)
    ->once()
    ->andReturn(new Book());
$book = $double->find(123);

有关方法调用声明期望的详细解释,请参阅文档中的 期望声明 部分。之后,你还可以在 替代 shouldReceive 语法 部分了解新的 allowsexpects 方法。

值得一提的是,设置期望的方法没有优劣之分。在底层,allowsexpectsshouldReceive 做的是同样的事情,有时用词更少,因此程序员个人喜好决定了使用哪种方式。

测试间谍 🕵️

默认情况下,使用 Mockery::mock 方法创建的所有测试替身都只会接受它们被配置为 allowexpect(或者换句话说,它们应该接收的)的调用。有时我们并不一定关心将被调用到对象的所有调用。为此,我们可以告诉 Mockery 忽略它未被告知期望或允许的任何调用。为此,我们可以对一个测试替身调用 shouldIgnoreMissing,或者我们可以使用 Mocker::spy 快捷方式创建双倍。

// $double = Mockery::mock()->shouldIgnoreMissing();
$double = Mockery::spy();

$double->foo(); // null
$double->bar(); // null

此外,有时我们希望在测试执行期间让对象接受任何调用,然后之后验证这些调用。为此,我们需要让我们的测试替身充当间谍。所有 Mockery 测试替身默认会记录对它们的调用,以便之后进行验证。

$double->baz(123);

$double->shouldHaveReceived()->baz(123); // null
$double->shouldHaveReceived()->baz(12345); // Uncaught Exception Mockery\Exception\InvalidCountException...

有关间谍的更多信息,请参阅文档中的 间谍 部分。

实用工具 🔌

全局助手

Mockery 随带了一些全局助手方法,你只需让 Mockery 声明它们即可。

Mockery::globalHelpers();

$mock = mock(Some::class);
$spy = spy(Some::class);

$spy->shouldHaveReceived()
    ->foo(anyArgs());

所有全局助手都包含在一个 !function_exists 调用中,以避免冲突。因此,如果你已经有了一个名为 spy 的全局函数,Mockery 会默默地跳过声明它自己的 spy 函数。

测试特性

由于 Mockery 具有代码生成功能,因此添加允许用户创建使用特定特性的对象的函数变得非常简单。特性定义的任何抽象方法都会被创建,并且可以像常规测试替身一样配置期望或存根。

trait Foo {
    function foo() {
        return $this->doFoo();
    }

    abstract function doFoo();
}

$double = Mockery::mock(Foo::class);
$double->allows()->doFoo()->andReturns(123);
$double->foo(); // int(123)

版本控制

Mockery 团队试图遵守 语义版本控制,但是,Mockery 的某些内部结构被认为是私有的,并且可以随时更改。即使一个类不是最终的,或者一个方法没有标记为私有,并不意味着它是我们在版本控制方案下保证的 API 的一部分。

替代运行时

Mockery 将尝试继续支持 HHVM,但不做出任何保证。

Mockery 的新家

⚠️️ 更新您的远程仓库!Mockery 已转移到新的位置。之前位于 padraic/mockery,现在位于 mockery/mockery。尽管您现有的仓库在执行任何操作时都会透明地重定向,但请花些时间过渡到新的 URL。

$ git remote set-url upstream https://github.com/mockery/mockery.git

upstream 替换为您本地使用的远程仓库名称;upstream 是一个常用名称,但您可能使用的是其他名称。运行 git remote -v 查看您实际使用的内容。