Я просто пытаюсь протестировать свое приложение Laravel.При кодировании проекта я пытался позаботиться о принципе «толстые сервисы, тощие контроллеры», поэтому каждая логика (включая логику БД) извлекается в классы обслуживания с интерфейсами и внедряется в контроллеры.Затем зависимости разрешаются с помощью контейнера IoC, предоставленного Laravel.
Мой вопрос касается проверки этих зависимостей интерфейса при тестировании контроллеров.Мне кажется, что внедрение зависимости никогда не разрешается должным образом тестом, оно всегда использует реализацию , которая вводится контейнером IoC, а не фальшивую.
Пример метода контроллера
public function index(ICrudService $crudService)
{
if (!\Auth::check()) {
return redirect()->route('login');
}
$comps = $crudService->GetAllCompetitions();
return view('competitions.index', ['competitions' => $comps]);
}
метод setUp
protected function setUp()
{
parent::setUp();
$this->faker = Faker\Factory::create();
// Create the mock objects
$this->user = \Mockery::mock(User::class);
$this->allComps = new Collection();
for ($i=0; $i<10; $i++)
{
$this->allComps->add(new Competition(['comp_id' => ++$i,
'comp_name' => $this->faker->unique()->company,
'comp_date' => "2018-11-07 17:25:41"]));
}
$this->user->shouldReceive('getAuthIdentifier')
->andReturn(1);
$this->competitionFake = \Mockery::mock(Competition::class);
// Resolve every Competition params with this fake
$this->app->instance(Competition::class, $this->competitionFake);
}
Тест
public function test_competition_index()
{
// Mock the Crud Service.
$fakeCrud = \Mockery::mock(ICrudService::class);
// Register the fake Crud Service to DI container.
$this->app->instance(ICrudService::class, $fakeCrud);
// Mock GetALllCompetitions method to return the fake collection.
$fakeCrud->shouldReceive('GetAllCompetitions')
->once()
->andReturn
($this->allComps);
// Authenticate the mock user.
$this->be($this->user);
// Send the request to the route, and assert if the view has competitions array.
$this->actingAs($this->user)->get('competitions')->assertStatus(200);
}
CrudServiceProvider
/**
* Register the application services.
*
* @return void
*/
public function register()
{
$this->app->bind('App\Services\Interfaces\ICrudService', function () {
return new CommonCrudService();
});
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return ['App\Services\Interfaces\ICrudService'];
}
Поведение
Тест не пройден из-за ответа HTTP 500 вместо 200. При отладке я мог видеть, чтоконтроллер все еще использует класс CommonCrudService, предоставляемый ServiceProvider, а не поддельный. Если я закомментирую CrudServiceProvider, поддельная служба передается контроллеру и возвращает указанную мной коллекцию. Конечно, я хочу сохранить контейнер для своего приложения.
Кто-нибудь испытывал подобные вещи?
Заранее большое спасибо!