Home » Php » php – Mock objects which support chaining methods

php – Mock objects which support chaining methods

Posted by: admin July 12, 2020 Leave a comment

Questions:

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.

How to&Answers:

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()
        );
    }
}

Answer:

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

Answer:

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.