Laravel测试中控制器的模拟接口依赖性

时间:2018-11-21 11:44:17

标签: php laravel testing dependency-injection phpunit

我只是想测试我的Laravel应用。在对项目进行编码时,我试图照顾“胖服务,瘦控制器”的原理,因此将每个逻辑(包括DB逻辑)提取到具有接口的服务类,并注入到控制器中。然后,依赖关系由Laravel提供的IoC容器解决。

我的问题是关于在测试控制器时模拟出这些接口依赖性。在我看来,依赖注入似乎从未被测试正确解决,它总是使用由IoC容器注入的实现,而不是伪造的。

控制器方法示例

public function index(ICrudService $crudService)
{
    if (!\Auth::check()) {
        return redirect()->route('login');
    }
    $comps = $crudService->GetAllCompetitions();

    return view('competitions.index', ['competitions' => $comps]);
}

设置方法

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,所以测试失败。调试时,我可以看到控制器仍在使用ServiceProvider提供的CommonCrudService类,而不是伪造的类。 如果我注释掉CrudServiceProvider,则虚假服务将传递到控制器,并返回我指定的集合。当然,我想保留应用程序的容器。

有人经历过这样的事情吗?

非常感谢!

0 个答案:

没有答案