PHPUnit中的Mocks vs Stubs

时间:2017-08-30 16:39:57

标签: unit-testing testing mocking phpunit stubs

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

如何在 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());

但在这种情况下,我正在验证状态,并说回复。

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

2 个答案:

答案 0 :(得分:33)

PHPUnit支持两种创建测试双精度的方法。在传统的PHPUnit模拟框架旁边,它现在支持开箱即用的预言。

PHPUnit Mocking Framework

createMock方法用于创建三个主要已知的测试双打。这是配置对象的方式,使其成为虚拟,存根或模拟。

您还可以使用模拟构建器创建测试存根(getMockBuilder返回模拟构建器)。这只是做同样事情的另一种方式,它允许你使用流畅的界面调整一些额外的模拟选项(更多信息见the documentation)。

虚拟

Dummy被传递,但从未实际调用过,或者如果它被调用,它会以默认答案(大多数是null)进行响应。它主要用于满足一系列参数。

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

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

存根

Stubs与查询类似的方法一起使用 - 返回事物的方法,但如果它们实际被调用则不重要。

$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上调用方法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();

答案 1 :(得分:0)

假人

首先,看看假人。如果您要求我记住我离开车钥匙的位置,则虚拟对象既是我的外观...也是在phpspec中添加带有类型提示的参数以获取测试双倍值时得到的对象...然后绝对不做任何事情。因此,如果我们得到一个双重测试,并且不添加任何行为,也不对其方法进行断言,则称为“虚拟对象”。

哦,在他们的文档中,您会看到类似$ prophecy-> reveal()的信息。这是我们无需担心的细节,因为phpspec会为我们处理这些细节。得分!

存根

一旦您开始控制一种方法的一种返回值,就可以了!此对象突然称为存根。在文档中:“存根是对象双精度型”-所有这些都称为测试双精度型或对象双精度型-当放在特定环境中时,它们会以特定方式表现。这是一种花哨的说法:一旦我们添加了其中的willReturn()一件事,它就会变成一个存根。

实际上,大多数文档都花在谈论存根以及精确控制其行为的不同方法,包括我们前面看到的Argument通配符。

模拟

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

间谍

最后,在底部,我们有间谍。间谍与模拟完全一样,只是在代码后添加期望值(例如,shouldHaveBeenCalledTimes()一样)。

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