Проблема с проверкой аргумента объекта издевательства

Рассмотрим примеры классов (извините за то, что они такие запутанные, но они настолько тонкие, насколько это возможно):

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:

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) оценивается как ложное. Примечание new RecordLookup(42) == new RecordLookup(42) оценивается как истинное, поэтому, если бы можно было как-то ослабить сравнение, это решило бы мою проблему.

Есть ли правильный способ обработки ожидаемых аргументов экземпляра в Mockery? Может я неправильно его использую?


person thodic    schedule 28.04.2015    source источник


Ответы (2)


Вы можете насмешливо сказать, что должен быть получен экземпляр 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');

Есть и другие варианты, подробно описанные в документации.

person gontrollez    schedule 28.04.2015
comment
Благодарю вас! На самом деле я только что нашел этот трек: github.com/padraic/mockery/issues/328 который затрагивает ту же тему. - person thodic; 28.04.2015
comment
@gontrollez, Спасибо, ты только что спас меня. - person Yevgeniy Afanasyev; 27.02.2020
comment
Еще раз спасибо, спустя год. - person Yevgeniy Afanasyev; 03.02.2021

В качестве альтернативы документация предлагает использовать equalTo($object) .

Например:

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