gpt4 book ai didi

php - 如何模拟对象工厂

转载 作者:可可西里 更新时间:2023-11-01 13:20:05 25 4
gpt4 key购买 nike

我经常使用工厂(请参阅 http://www.php.net/manual/en/language.oop5.patterns.php 了解模式)来提高我们代码的可测试性。一个简单的工厂看起来像这样:

class Factory
{
public function getInstanceFor($type)
{
switch ($type) {
case 'foo':
return new Foo();
case 'bar':
return new Bar();
}
}
}

这是一个使用该工厂的示例类:

class Sample
{
protected $_factory;

public function __construct(Factory $factory)
{
$this->_factory = $factory;
}

public function doSomething()
{
$foo = $this->_factory->getInstanceFor('foo');
$bar = $this->_factory->getInstanceFor('bar');
/* more stuff done here */
/* ... */
}
}

现在为了进行正确的单元测试,我需要模拟将返回类 stub 的对象,而这正是我遇到困难的地方。我认为可以这样做:

class SampleTest extends PHPUnit_Framework_TestCase
{
public function testAClassUsingObjectFactory()
{
$fooStub = $this->getMock('Foo');
$barStub = $this->getMock('Bar');

$factoryMock = $this->getMock('Factory');

$factoryMock->expects($this->any())
->method('getInstanceFor')
->with('foo')
->will($this->returnValue($fooStub));

$factoryMock->expects($this->any())
->method('getInstanceFor')
->with('bar')
->will($this->returnValue($barStub));
}
}

但是当我运行测试时,这是我得到的:

F

Time: 0 seconds, Memory: 5.25Mb

There was 1 failure:

1) SampleTest::testDoSomething
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-bar
+foo

FAILURES!
Tests: 1, Assertions: 0, Failures: 1.

很明显,通过这种方式让模拟对象根据传递的方法参数返回不同的值是不可能的。

如何做到这一点?

最佳答案

问题是 PHPUnit Mocking 不允许你这样做:

$factoryMock->expects($this->any())
->method('getInstanceFor')
->with('foo')
->will($this->returnValue($fooStub));

$factoryMock->expects($this->any())
->method('getInstanceFor')
->with('bar')
->will($this->returnValue($barStub));

每个 ->method(); 只能有一个 expects。它不知道 ->with() 的参数不同!

所以你只需用第二个覆盖第一个->expects()。这就是这些断言的实现方式,而不是人们所期望的。但也有解决方法。


您需要用两种行为/返回值定义一个期望!

参见:Mock in PHPUnit - multiple configuration of the same method with different arguments

根据您的问题调整示例时,它可能如下所示:

$fooStub = $this->getMock('Foo');
$barStub = $this->getMock('Bar');

$factoryMock->expects($this->exactly(2))
->method('getInstanceFor')
->with($this->logicalOr(
$this->equalTo('foo'),
$this->equalTo('bar')
))
->will($this->returnCallback(
function($param) use ($fooStub, $barStub) {
if($param == 'foo') return $fooStub;
return $barStub;
}
));

关于php - 如何模拟对象工厂,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6731024/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com