Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mockery object argument validation issue

Consider the example classes (apologies for it being so convoluted, but it's as slim as possible):

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

In which I want to test App whilst mocking RecordPage:

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

Note: the expected object argument ->with(new RecordLookup(42)).

I would expect this to pass however Mockery returns throws 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.

I'm assuming this is because a strict comparison is used for the arguments expected through with() and new RecordLookup(42) === new RecordLookup(42) evaluates as false. Note new RecordLookup(42) == new RecordLookup(42) evaluates as true so if there was someway of relaxing the comparison it would fix my problem.

Is there a proper way to handle expected instance arguments in Mockery? Maybe I'm using it incorrectly?

like image 265
thodic Avatar asked Apr 28 '15 11:04

thodic


1 Answers

You can tell mockery that a RecordLookup instance (any) should be received:

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

But this will match any instance of RecordLookup. If you need to dig inside the object and check if it's value is 42, then you can employ a custom validator:

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

There are more options, well explained in the docs.

like image 52
gontrollez Avatar answered Nov 11 '22 23:11

gontrollez