Зависимость интерфейса контроллеров при тестировании Laravel - PullRequest
0 голосов
/ 21 ноября 2018

Я просто пытаюсь протестировать свое приложение 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, поддельная служба передается контроллеру и возвращает указанную мной коллекцию. Конечно, я хочу сохранить контейнер для своего приложения.

Кто-нибудь испытывал подобные вещи?

Заранее большое спасибо!

...