mockery/mockery

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

安装: 351,245,887

依赖: 23,633

建议者: 45

安全: 0

星标: 10,611

关注者: 73

分叉: 461

开放问题: 106


README

Build Status Supported PHP Version Code Coverage Type Coverage Latest Stable Version Total Downloads

Mockery 是一个简单而灵活的 PHP 模拟对象框架,用于与 PHPUnit、PHPSpec 或任何其他测试框架进行单元测试。其核心目标是提供一个具有简洁 API 的测试替身框架,该 API 能够使用人类可读的领域特定语言 (DSL) 清晰地定义所有可能的对象操作和交互。Mockery 设计为 PHPUnit 的 phpunit-mock-objects 库的替代品,易于与 PHPUnit 集成,并且可以在不破坏世界的情况下与 phpunit-mock-objects 同时运行。

Mockery 采用新的 BSD 许可证发布。

安装

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

composer require --dev mockery/mockery

文档

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

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

PHPUnit 集成

如果使用 PHPUnit,Mockery 附带了一些辅助工具。您可以扩展 Mockery\Adapter\Phpunit\MockeryTestCase 类,而不是 PHPUnit\Framework\TestCase,或者如果您已经为您的测试使用自定义基类,请查看 Mockery\Adapter\Phpunit 命名空间中可用的 traits。

测试替身

测试替身(通常称为模拟)模拟真实对象的行为。它们通常用于提供测试隔离、替代尚未存在的对象,或允许在不进行实际实现的情况下探索性地设计类 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);

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

方法存根 🎫

方法存根是一种机制,使您的测试替身对某些方法调用返回预设的响应。使用存根时,您不必关心方法被调用多少次,或者是否被调用。存根用于向正在测试的系统提供间接输入。

$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检查该方法是否按预期调用,可以使用Mockery::close方法。一种方法是将其添加到PHPUnit中的tearDown方法中。

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

expects()方法会自动设置一个期望,即方法调用(及匹配的参数)仅调用一次。如果您期望更多的调用,您可以更改这个设置。

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

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

对于 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的一些内部实现被认为是私有的,并且可能会随时进行更改。一个类不是final的,或者一个方法没有被标记为private,并不意味着它是我们在版本控制方案下保证的API的一部分。

替代运行时

Mockery 1.3是最后一个支持HHVM 3和PHP 5的版本。不支持HHVM 4及以上版本。

Mockery的新家

⚠️️ 更新您的远程仓库!Mockery已经迁移到新位置。虽然它曾经位于padraic/mockery,但现在位于mockery/mockery。虽然您的现有仓库会在任何操作中透明地重定向,但请花些时间过渡到新的URL。

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

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