【发布时间】:2011-10-07 13:03:50
【问题描述】:
我经常使用工厂(请参阅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 */
/* ... */
}
}
现在,为了进行正确的单元测试,我需要模拟将为类返回存根的对象,这就是我卡住的地方。我认为可以这样做:
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.
所以显然不可能让模拟对象以这种方式根据传递的方法参数返回不同的值。
如何做到这一点?
【问题讨论】:
-
不确定出了什么问题。您的代码看起来应该“正常工作”。您可能还想查看抽象工厂模式。如果它可以在 PHP 中工作(我对 PHP 中的多态支持一无所知),那么您就不必针对模拟工厂编写期望。您可以创建并传递返回模拟 foo/bar 实例的派生工厂类型实例。
-
您还可以查看您的代码是否可以使用更直接的依赖注入来代替。您只需传递
foo和bar的实例,而不是传递工厂。 -
@Merlyn 绝对!如果在编程时知道需要哪些依赖项,直接将它们传递进来会更容易/更好。只有在运行时不知道所需的类或工厂更复杂(传递运行时参数等)时才应使用这种方式。关于这个主题有一个很棒的视频:youtube.com/watch?v=RlfLCWKxHJ0
标签: php phpunit factory-pattern