I use Factories (see http://www.php.net/manual/en/language.oop5.patterns.php for the pattern) a lot to increase the testability of our code. A simple factory could look like this:
class Factory
{
public function getInstanceFor($type)
{
switch ($type) {
case 'foo':
return new Foo();
case 'bar':
return new Bar();
}
}
}
Here is a sample class using that factory:
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 */
/* ... */
}
}
Now for proper unit testing I need to mock the object that will return stubs for the classes, and that is where I got stuck. I thought it would be possible to do it like this:
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));
}
}
But when I run the test, this is what I get:
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.
So obviously it is not possible to let a mock object return different values depending on the passed method arguments this way.
How can this be done?
foo
andbar
. – Protostele