dousong5492
2010-11-20 12:43
采纳率: 100%
浏览 31
已采纳

模拟支持链接方法的对象

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.

  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

3条回答 默认 最新

  • dsfvsdfv23599 2010-11-20 14:50
    已采纳

    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()
            );
        }
    }
    
    已采纳该答案
    打赏 评论
  • dongxuanjiao0795 2010-11-20 13:42

    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.

    打赏 评论
  • duanfu5239 2014-11-28 02:17

    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

    打赏 评论

相关推荐 更多相似问题