Laravel 7 частичная имитация красноречивой модели не работает с __construct (), но никаких ожиданий не было указано - PullRequest
0 голосов
/ 09 июля 2020

Я использую Laravel 7 и пытаюсь частично имитировать красноречивую модель ..

В мой контроллер введена красноречивая зависимость модели:

use App\Models\Ticket;

class TicketsController extends Controller
{
    /** @var Ticket */
    private $tickets;

    public function __construct(Ticket $ticket) {
        $this->tickets = $ticket;
    }

    public function get() {
        $tickets = $this->tickets::whereNull('staff_id')
            ->where('status', '!=', $this->tickets::STATUS_CLOSED)
            ->orderBy('created_at', 'desc')
            ->get();
    }
}

Модульный тест:

use App\Models\Ticket;

    $this->partialMock(Ticket::class, function($mock) {
        $mock->shouldReceive('get')
            ->once()
            ->andReturn([]);
    });

    $response = $this->json('get', route('tickets'));

    $response->assertOk();

Сбой с:

тестирование. ОШИБКА: Получен Mockery_0_App_Models_Ticket :: __ construct (), но никаких ожиданий не было указано {"исключение": "[объект] (Mockery \ Exception \ BadMethodCallException (code: 0): Получен Mockery_0_App_Models_Ticket :: __ construct (), но в /opt/project/vendor/mockery/mockery/library/Mockery/Loader/EvalLoader.php(34): eval () ' d код: 911)

Также пытался изменить тест для этого:

    $ticketsMock = Mockery::mock(Ticket::class);
    $ticketsMock
        ->makePartial()
        ->shouldReceive('get')
        ->once()
        ->andReturn([]);

    $this->instance(Ticket::class, $ticketsMock);

Но получаю точно такую ​​же ошибку ..

Если я заменю mock на non частичный и подделать все вызовы методов в модели, которая работает нормально ... но некоторые красноречивые запросы будут довольно длинными, и я пытаюсь сделать это с помощью частичного макета, поэтому мне не нужно подделывать каждый связанный вызов, например ->shouldReceive('something')->andReturnSelf()

1 Ответ

0 голосов
/ 09 июля 2020

Проблема с частичным состоит в том, что whereNull возвращает QueryBuilder, а не модель билета.

Я считаю хорошим решением издеваться над цепями деметра . Вы можете имитировать беглые вызовы, выполнив выражение его в строке whereNull->where->orderBy->get. У меня есть следующий пример для локальной работы.

$this->mock(Ticket::class, function($mock) {
    $mock->shouldReceive('whereNull->where->orderBy->get')
        ->once()
        ->andReturn([]);
});

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

Я немного изменил метод контроллера, так как вы вызывали метод для объектов статически. Чтобы убедиться, что это работает, мой лог c контроллера был таким.

$tickets = $this->tickets->whereNull('staff_id')
    ->where('status', '!=', Ticket::STATUS_CLOSED)
    ->orderBy('created_at', 'desc')
    ->get();
...