我正在创建一个Laravel控制器,其中一个随机字符串生成器接口被注入到其中一个方法。然后在AppServiceProvider中注册一个实现。
控制器使用随机字符串作为输入,将数据保存到数据库。因为它是随机的,所以我不能像这样测试它(使用MakesHttpRequests
):
$this->post('/api/v1/do_things', ['email' => $this->email])
->seeInDatabase('things', ['email' => $this->email, 'random' => 'abc123']);
因为我不知道'abc123'在使用实际的随机生成器时会是什么。所以我创建了Random接口的另一个实现,它总是返回'abc123',所以我可以对它进行断言。
问题是:我如何在测试时绑定到这个假生成器?我试着做
$this->app->bind('Random', 'TestableRandom');
,但它仍然使用我在AppServiceProvider中注册的实际生成器。什么好主意吗?关于如何测试这样的东西,我是否完全走错了轨道?
谢谢!
您有两个选择:
使用条件来绑定实现:
class AppServiceProvider extends ServiceProvider {
public function register() {
if($this->app->runningUnitTests()) {
$this->app->bind('Random', 'TestableRandom');
} else {
$this->app->bind('Random', 'RealRandom');
}
}
}
第二个选项是在测试中使用mock
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',
]);
}
如果您决定使用模拟路由。一定要签出mock文档:
http://docs.mockery.io/en/latest/reference/expectations.htmlFrom laracast
class ApiClientTest extends TestCase
{
use HttpMockTrait;
private $apiClient;
public function setUp()
{
parent::setUp();
$this->setUpHttpMock();
$this->app->bind(ApiConfigurationInterface::class, FakeApiConfiguration::class);
$this->apiClient = $this->app->make(ApiClient::class);
}
/** @test */
public function example()
{
dd($this->apiClient);
}
}
结果AppApiClient^ {#355
-apiConfiguration: TestsFakeApiConfiguration^ {#356}
}
https://laracasts.com/discuss/channels/code-review/laravel-58-interface-binding-while-running-tests?page=1& replyId = 581880