Mockery对象参数验证问题

时间:2015-04-28 11:13:19

标签: php phpunit mockery

考虑一下示例类(对于它如此复杂而道歉,但它尽可能地渺茫):

class RecordLookup
{
    private $records = [
        13 => 'foo',
        42 => 'bar',
    ];

    function __construct($id)
    {
        $this->record = $this->records[$id];
    }

    public function getRecord()
    {
        return $this->record;
    }
}

class RecordPage
{
    public function run(RecordLookup $id)
    {
        return "Record is " . $id->getRecord();
    }
}

class App
{
    function __construct(RecordPage $page, $id)
    {
        $this->page = $page;
        $this->record_lookup = new RecordLookup($id);
    }

    public function runPage()
    {
        return $this->page->run($this->record_lookup);
    }
}

我想在模拟RecordPage时测试App:

class AppTest extends \PHPUnit_Framework_TestCase
{
    function testAppRunPage()
    {
        $mock_page = \Mockery::mock('RecordPage');

        $mock_page
            ->shouldReceive('run')
            ->with(new RecordLookup(42))
            ->andReturn('bar');

        $app = new App($mock_page, 42);

        $this->assertEquals('Record is bar', $app->runPage());
    }
}

注意:预期的对象参数->with(new RecordLookup(42))

我希望这会通过但是Mockery返回抛出No matching handler found for Mockery_0_RecordPage::run(object(RecordLookup)). Either the method was unexpected or its arguments matched no expected argument list for this method

我假设这是因为通过with()预期的参数使用了严格的比较,而new RecordLookup(42) === new RecordLookup(42)评估为false。注意new RecordLookup(42) == new RecordLookup(42)评估为真,所以如果有人放松比较,那将解决我的问题。

有没有一种正确的方法来处理Mockery中的预期实例参数?也许我错误地使用它?

2 个答案:

答案 0 :(得分:8)

你可以告诉嘲笑应该收到一个RecordLookup实例(任何):

$mock_page
        ->shouldReceive('run')
        ->with(\Mockery::type('RecordLookup'))
        ->andReturn('bar');

但是这将匹配RecordLookup的任何实例。如果您需要挖掘对象内部并检查它的值是否为42,那么您可以使用自定义验证器:

$mock_page
        ->shouldReceive('run')
        ->with(\Mockery::on(function($argument) {
            return 
                 $argument instanceof RecordLookup && 
                 'bar' == $argument->getRecord()
            ;
        }))
        ->andReturn('bar');

还有更多选项,在the docs中有详细解释。

答案 1 :(得分:0)

作为替代方案,documentation 建议使用 equalTo($object)。

例如:

$userRepository->shouldReceive('create')
            ->once()
            ->with(\Hamcrest\Core\IsEqual::equalTo(
                new User(0, "Test", "Dummy", "fakelogin")));