Reputation: 11149
I'm wondering if there's a fairly concise way of mocking objects which support chaining of methods... so for example, a database query object might have a method call that looks like this:
$result = $database->select('my_table')->where(array('my_field'=>'a_value'))->limit(1)->execute();
The problem comes if I have to mock two different select queries so that they return different results. Any ideas?
This is specifically about PHPUnit, but experiences from other unit testing frameworks will help.
Upvotes: 7
Views: 4109
Reputation: 4962
I know its an old question, but it might help more to future googler's.
I was also having problems in finding a framework that will provide simple and easy syntax for mocking & stubbing method chainning. then I've decided to write a simple and easy-to-use mocking library.
Usage example:
// Creating a new mock for SimpleClassForMocking
$mock = ShortifyPunit::mock('SimpleClassForMocking');
ShortifyPunit::when($mock)->first_method()
->second_method(2,3)->returns(1);
ShortifyPunit::when($mock)->first_method()
->second_method(2,3,4)->returns(2);
ShortifyPunit::when($mock)->first_method(1)
->second_method(2,3,4)->returns(3);
ShortifyPunit::when($mock)->first_method(1,2,3)
->second_method(1,2)->third_method()->returns(4);
$mock->first_method()->second_method(2,3); // returns 1
$mock->first_method()->second_method(2,3,4); // returns 2
$mock->first_method(1)->second_method(2,3,4); // returns 3
$mock->first_method(1,2,3)->second_method(1,2)->third_method(); // return 4
GitHub:
https://github.com/danrevah/ShortifyPunit#stubbing-method-chanining
Upvotes: 1
Reputation: 316969
I am not sure this is what you are looking for, so please leave a comment:
class StubTest extends PHPUnit_Framework_TestCase
{
public function testChainingStub()
{
// Creating the stub with the methods to be called
$stub = $this->getMock('Zend_Db_Select', array(
'select', 'where', 'limit', 'execute'
), array(), '', FALSE);
// telling the stub to return a certain result on execute
$stub->expects($this->any())
->method('execute')
->will($this->returnValue('expected result'));
// telling the stub to return itself on any other calls
$stub->expects($this->any())
->method($this->anything())
->will($this->returnValue($stub));
// testing that we can chain the stub
$this->assertSame(
'expected result',
$stub->select('my_table')
->where(array('my_field'=>'a_value'))
->limit(1)
->execute()
);
}
}
You can combine this with expectations:
class StubTest extends PHPUnit_Framework_TestCase
{
public function testChainingStub()
{
// Creating the stub with the methods to be called
$stub = $this->getMock('Zend_Db_Select', array(
'select', 'where', 'limit', 'execute'
), array(), '', FALSE);
// overwriting stub to return something when execute is called
$stub->expects($this->exactly(1))
->method('execute')
->will($this->returnValue('expected result'));
$stub->expects($this->exactly(1))
->method('limit')
->with($this->equalTo(1))
->will($this->returnValue($stub));
$stub->expects($this->exactly(1))
->method('where')
->with($this->equalTo(array('my_field'=>'a_value')))
->will($this->returnValue($stub));
$stub->expects($this->exactly(1))
->method('select')
->with($this->equalTo('my_table'))
->will($this->returnValue($stub));
// testing that we can chain the stub
$this->assertSame(
'expected result',
$stub->select('my_table')
->where(array('my_field'=>'a_value'))
->limit(1)
->execute()
);
}
}
Upvotes: 14
Reputation: 35308
This might not be the answer you're looking for, but I wrote a mock object framework a couple of years back that will handle this sort of "depends on the input" assertion fine:
http://code.google.com/p/yaymock/
http://code.google.com/p/yaymock/wiki/Expectations
I wrote it for use in the unit tests backing Swift Mailer but it hasn't been widely adopted by any other projects (that I know of). The purpose was to provide better control and introspection of mock object invocations than that provided by PHPUnit and SimpleTest.
Upvotes: 0