模拟支持链接方法的对象

时间:2010-11-20 12:43:18

标签: php unit-testing mocking phpunit

我想知道是否有一种相当简洁的方法来模拟支持方法链接的对象...例如,数据库查询对象可能有一个如下所示的方法调用:

$result = $database->select('my_table')->where(array('my_field'=>'a_value'))->limit(1)->execute();

如果我必须模拟两个不同的选择查询以便它们返回不同的结果,则会出现问题。有什么想法吗?

这是关于PHPUnit的,但其他单元测试框架的经验会有所帮助。

3 个答案:

答案 0 :(得分:14)

我不确定这是你在找什么,所以请发表评论:

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

您可以将其与期望结合起来:

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

答案 1 :(得分:1)

我知道这是一个古老的问题,但它可能对未来的Google员工有所帮助。

我在找到一个框架时遇到了问题,该框架将为模拟提供简单易用的语法。存根方法链接。然后我决定编写一个简单易用的模拟库。

用法示例:

 // 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

答案 2 :(得分:0)

这可能不是您正在寻找的答案,但我在几年前编写了一个模拟对象框架,它将处理这种“取决于输入”的断言:

http://code.google.com/p/yaymock/

http://code.google.com/p/yaymock/wiki/Expectations

我把它写在支持Swift Mailer的单元测试中,但它还没有被其他任何项目广泛采用(我知道)。目的是提供比PHPUnit和SimpleTest提供的模拟对象调用更好的控制和内省。