Насмешливые обратные вызовы в Laravel 4 (насмешка)

В настоящее время я пишу тесты для пакета в Laravel 4.

Я издеваюсь над Illuminate\Database\Query\Builder, который работает почти все время, за исключением случаев, когда метод where использует обратный вызов, я не могу проверить, вызываются ли методы внутри обратного вызова.

Я надеялся, что кто-нибудь из вас сможет пролить свет.

$query = \Mockery::mock('Illuminate\Database\Query\Builder', function ($mock) {
    /** @var \Mockery\Mock $mock */
    $mock->shouldReceive('where');
    $mock->shouldReceive('orWhere')->twice();
});

И фактический метод where, который должен вызывать orWhere. Примечание. Этот макет построителя передается классу ниже.

$builder = new LaravelBuilder($query);

Который затем вызывает $builder->filter(), который содержит приведенный ниже код.

$this->query->where(function ($query) use ($filterData) {
    /** @var \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder $query */
    foreach($filterData['columns'] as $colData) {
        /** @var \Samvaughton\Ldt\Column $column */
        $column = $colData['column'];

        // See if this column is searchable
        if (!$column->isSearchable() || !$colData['searchable']) continue;

        // If the individual column term is empty, use the main term
        $term = (empty($colData['term'])) ? $filterData['term'] : $colData['term'];

        // Actually apply the filter
        $query->orWhere($column->getSqlColumn(), "LIKE", "%{$term}%");
    }
});

Основная часть - это нижний бит $query->orWhere, тесты PHPUnit каждый раз терпят неудачу, поскольку он не запускает orWhere ни разу. Прежде чем вы скажете, что он может не дойти до его выполнения из-за continue, данные, которые я передаю, позволят это сделать.

Я подозреваю, что это связано с тем, как я издеваюсь над методом where в первую очередь. Если я включу exit перед foreach, он не будет выполняться, что указывает на то, что он даже ничего не запускает внутри обратного вызова. Я знаю, что это поведение по умолчанию, но как мне заставить Mockery запускать тот же/похожий обратный вызов?

Я пытался использовать частичные макеты, используя shouldExpect, но не совсем понимаю. Я также пытался искать, но не повезло с этим сценарием.

Было бы здорово, если бы я мог научиться использовать насмешки в обратных вызовах.


person SamV    schedule 20.12.2013    source источник


Ответы (1)


Итак, я думаю, что это можно сделать лучше, но я прибегнул к частичному издевательству над построителем запросов Laravel.

См. строку 324 в Illuminate\Database\Query\Builder

При использовании замыкания Laravel порождает новый построитель запросов, который также необходимо имитировать. Вот код, который работал:

$query = \Mockery::mock('Illuminate\Database\Query\Builder', function ($mock) {
    /** @var \Mockery\Mock $mock */
    $mock->makePartial();
    $mock->shouldReceive('where')->once()->passthru();
    $mock->shouldReceive('newQuery')->andReturn(
        \Mockery::mock('Illuminate\Database\Query\Builder', function ($mock) {
            /** @var \Mockery\Mock $mock */
            $mock->makePartial();
            $mock->shouldReceive('orWhere')->twice();
        })
    );
});

Мне нужно было использовать makePartial(), поэтому построитель запросов сохранил свою первоначальную функциональность для замыканий (что не соответствует модульному тестированию), так что это не лучшее решение. Отсюда я издеваюсь над методом newQuery, который вызывается для порождения нового экземпляра построителя запросов, который я затем имитирую в аналогичном формате.

person SamV    schedule 21.12.2013
comment
Это действительно помогло мне! Я не могу найти ничего в документах Mockery о передаче замыкания в качестве второго аргумента mock. Как вы узнали, что делать это? - person alexw; 22.07.2017