Mockery object argument validation issue
Asked Answered
J

2

8

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?

Jamille answered 28/4, 2015 at 11:13 Comment(0)
C
17

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.

Caldwell answered 28/4, 2015 at 13:18 Comment(3)
Thank you! I actually just found this issue track: github.com/padraic/mockery/issues/328 which covers the same topic.Jamille
@gontrollez, Thank you, you just saved me.Swage
Thank you again, a year later.Swage
G
1

As an alternative, the documentation proposes to use equalTo($object).

For example:

$userRepository->shouldReceive('create')
            ->once()
            ->with(\Hamcrest\Core\IsEqual::equalTo(
                new User(0, "Test", "Dummy", "fakelogin")));
Guttery answered 12/7, 2021 at 0:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.