在Laravel中,如何在测试时为服务容器提供另一个实现?

Luc*_*sis 6 php laravel laravel-5

我正在创建一个Laravel控制器,其中一个随机字符串生成器接口被注入其中一个方法.然后在AppServiceProvider中我正在注册一个实现.这很好用.

控制器使用随机字符串作为输入将数据保存到数据库.由于它是随机的,我无法测试它(使用MakesHttpRequests),如下所示:

$this->post('/api/v1/do_things', ['email' => $this->email])
->seeInDatabase('things', ['email' => $this->email, 'random' => 'abc123']);
Run Code Online (Sandbox Code Playgroud)

因为我不知道使用实际随机发生器时'abc123'会是什么.所以我创建了另一个随机接口的实现,它始终返回'abc123',所以我可以断言.

问题是:如何在测试时绑定到这个假发生器?我试着这样做

$this->app->bind('Random', 'TestableRandom');
Run Code Online (Sandbox Code Playgroud)

在测试之前,它仍然使用我在AppServiceProvider中注册的实际生成器.有任何想法吗?关于如何测试这样的事情我完全错了吗?

谢谢!

scr*_*bmx 15

你有几个选择:

使用条件绑定实现:

class AppServiceProvider extends ServiceProvider {

    public function register() {
        if($this->app->runningUnitTests()) {
           $this->app->bind('Random', 'TestableRandom');
        } else {
           $this->app->bind('Random', 'RealRandom');
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

第二个选项是在测试中使用模拟

public function test_my_controller () {
    // Create a mock of the Random Interface
    $mock = Mockery::mock(RandomInterface::class);

    // Set our expectation for the methods that should be called
    // and what is supposed to be returned
    $mock->shouldReceive('someMethodName')->once()->andReturn('SomeNonRandomString');

    // Tell laravel to use our mock when someone tries to resolve
    // an instance of our interface
    $this->app->instance(RandomInterface::class, $mock);

    $this->post('/api/v1/do_things', ['email' => $this->email])
         ->seeInDatabase('things', [
             'email' => $this->email, 
             'random' => 'SomeNonRandomString',
         ]);
}
Run Code Online (Sandbox Code Playgroud)

如果你决定采用模拟路线.务必查看嘲弄文档:

http://docs.mockery.io/en/latest/reference/expectations.html

  • 我认为要走的路是第二种选择.不应该考虑第一种选择.它不仅难看,而且必须难以维护. (7认同)