Я часто использую Фабрики (см. 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.
Очевидно, что невозможно позволить фиктивному объекту возвращать разные значения в зависимости от переданного метода аргументы таким образом.
Как это можно сделать?