Как правильно мокнуть коллекцию моделей laravel?
внутри аrtisan команды есть строка внутри конструктора
$this->transfers = TransferCrypto::where(["state" => 1])->with('ref_withdraw.user')->get();
как правильно её мокнуть в unit тесте без фабрик?
мой топорный вариант
$mockQueryBuilder = Mockery::mock('Illuminate\Database\Eloquent\Builder');
$mockQueryBuilder
->shouldReceive('where')
->with(['state' => 1])
->once()
->andReturnSelf();
$mockQueryBuilder
->shouldReceive('with')
->with('ref_withdraw.user')
->once()
->andReturnSelf();
$mockQueryBuilder
->shouldReceive('get')
->once()
->andReturn(collect([
(object)[
'id' => 1, 'state' => 1,
],
(object)['id' => 2, 'state' => 1]
]));
$mockTransferCrypto = Mockery::mock('overload:App\TransferCrypto'); // or 'alias'
$mockTransferCrypto
->shouldReceive('where')
->with(['state' => 1])
->once()
->andReturn($mockQueryBuilder);
как правильно и красиво это зарефакторить?
Ответы (1 шт):
Автор решения: mydls1
→ Ссылка
Твой подход в целом верен, но его можно сделать более лаконичным и читаемым, убрав часть дублирующегося кода и улучшив структурированность. Вот пример рефакторинга:
- Объедини мокирование вызовов where, with и get в одну последовательность.
- Перемести мокирование метода where непосредственно на класс TransferCrypto.
Результат выглядит так:
// Мокируем запрос и его цепочку вызовов
$mockQueryBuilder = Mockery::mock('Illuminate\Database\Eloquent\Builder')
->shouldReceive('with')
->with('ref_withdraw.user')
->andReturnSelf()
->getMock();
$mockQueryBuilder
->shouldReceive('get')
->andReturn(collect([
(object)[ 'id' => 1, 'state' => 1 ],
(object)[ 'id' => 2, 'state' => 1 ]
]));
// Мокируем класс TransferCrypto и метод where
$mockTransferCrypto = Mockery::mock('overload:App\TransferCrypto')
->shouldReceive('where')
->with(['state' => 1])
->andReturn($mockQueryBuilder)
->getMock();
- Использование ->getMock(): помогает создать окончательный мок-объект без необходимости дополнительных вызовов.
- Цепочка мокирования: в Mockery можно сразу комбинировать последовательные вызовы, чтобы сделать код компактнее.
- Сокращение кода: определение и вызов with и get теперь находятся в одном блоке, что упрощает восприятие логики.