36

我知道存根验证状态和模拟验证行为。

如何在PHPUnit中进行模拟以验证方法的行为?Phpunit 没有验证方法(verify()),而且我不知道如何制作一个 moks 是PHPUnit

在文档中,很好地解释了创建存根:

// Create a stub for the SomeClass class.
$stub = $this->createMock(SomeClass::class);

// Configure the stub.
$stub
    ->method('doSomething')
    ->willReturn('foo');

// Calling $stub->doSomething() will now return 'foo'.
$this->assertEquals('foo', $stub->doSomething());

但在这种情况下,我正在验证状态,说返回答案。

创建模拟和验证行为的示例如何?

4

2 回答 2

88

PHPUnit 过去支持两种开箱即用的创建测试替身的方法。在遗留的 PHPUnit 模拟框架旁边,我们也可以选择预言。

PHPUnit 9 中删除了预言支持,但可以通过安装phpspec/prophecy-phpunit.

PHPUnit 模拟框架

createMock方法用于创建三个最知名的测试替身。这是您配置对象的方式,使其成为虚拟对象、存根或模拟对象。

您还可以使用模拟构建器创建测试存根(getMockBuilder返回模拟构建器)。这只是做同样事情的另一种方式,让您可以使用流畅的界面调整一些额外的模拟选项(有关更多信息,请参阅文档)。

假的

Dummy 被传递,但从未真正被调用,或者如果它被调用,它会以默认答案响应(主要是null)。它的存在主要是为了满足一系列参数。

$dummy = $this->createMock(SomeClass::class);

// SUT - System Under Test
$sut->action($dummy);

存根

存根与类似查询的方法一起使用——返回事物的方法,但它们是否被实际调用并不重要。

$stub = $this->createMock(SomeClass::class);
$stub->method('getSomething')
    ->willReturn('foo');

$sut->action($stub);

嘲笑

模拟与类似命令的方法一起使用 - 调用它们很重要,我们不太关心它们的返回值(命令方法通常不返回任何值)。

$mock = $this->createMock(SomeClass::class);
$mock->expects($this->once())
    ->method('doSomething')
    ->with('bar');

$sut->action($mock);

在您的测试方法完成执行后,将自动验证预期。doSomething在上面的示例中,如果方法没有被调用 on SomeClass,或者使用与您配置的参数不同的参数调用它,则测试将失败。

间谍

不支持。

预言

PHPUnit 现在开箱即用地支持 Prophecy,因此您可以将其用作传统模拟框架的替代方案。同样,您配置对象的方式使其成为特定类型的测试替身。

假的

$dummy = $this->prophesize(SomeClass::class);

$sut->action($dummy->reveal());

存根

$stub = $this->prophesize(SomeClass::class);
$stub->getSomething()->willReturn('foo');

$sut->action($stub->reveal());

嘲笑

$mock = $this->prophesize(SomeClass::class);
$mock->doSomething('bar')->shouldBeCalled();

$sut->action($mock->reveal());

间谍

$spy = $this->prophesize(SomeClass::class);

// execute the action on system under test
$sut->action($spy->reveal());

// verify expectations after 
$spy->doSomething('bar')->shouldHaveBeenCalled();
于 2017-08-31T07:22:33.590 回答
3

假人

首先,看看假人。如果你让我记住我把车钥匙放在哪里了,一个虚拟对象就是我的样子......如果你在 phpspec 中添加一个带有类型提示的参数以获得测试替身,你得到的对象也是......然后绝对不做任何事情。因此,如果我们得到一个测试替身并且不添加任何行为并且不对其方法进行断言,则它被称为“虚拟对象”。

哦,在他们的文档中,你会看到像 $prophecy->reveal() 这样的东西。这是一个我们不需要担心的细节,因为 phpspec 会为我们解决这个问题。分数!

存根

一旦你开始控制甚至一个方法的一个返回值......繁荣!这个对象突然被称为存根。来自文档:“存根是对象替身”——所有这些东西都被称为测试替身或对象替身——当放在特定环境中时,它们会以特定方式运行。这是一种奇特的说法:只要我们添加了其中一个 willReturn() 东西,它就会变成一个存根。

实际上,大部分文档都在讨论存根和控制其行为方式的不同方法,包括我们之前看到的参数通配符。

模拟

如果你继续往下读,你会发现下一个东西是“模拟”。当你调用 shouldBeCalled() 时,一个对象变成了一个 mock。因此,如果您想添加一个方法被调用一定次数的断言,并且您想将该断言放在实际代码之前 - 使用 shouldBeCalledTimes() 或 shouldBeCalled() - 恭喜!您的对象现在称为模拟对象。

间谍

最后,在底部,我们有间谍。spy 与 mock 完全一样,除了它是在代码之后添加期望 - 就像 shouldHaveBeenCalledTimes() 一样。

https://symfonycasts.com/screencast/phpspec/doubles-dummies-mocks-sies

于 2020-05-04T06:53:17.100 回答