我正在用Laravel写一个小的API,部分是为了学习这个框架。我想我在文档中发现了一个巨大的漏洞,但这可能是由于我不理解“Laravel方式”来做我想做的事情。
我正在编写一个HTTP API,用于在Linux服务器上列出、创建和删除系统用户。结构是这样的:
- 到
/v1/users
的路由将GET
、POST
和DELETE
动词分别连接到控制器方法get
、create
和delete
。 - 控制器
App\Http\Controllers\UserController
实际上并不运行系统调用,这是由服务App\Services\Users
完成的。 - 该服务由ServiceProvider
App\Providers\Server\Users
创建,该ServiceProviderApp\Providers\Server\Users
在延迟的基础上注册服务的singleton
。 - 服务由Laravel自动示例化并自动注入到控制器的构造函数中。
好了,这一切工作。我也写了一些测试代码,像这样:
public function testGetUsers()
{
$response = $this->json('GET', '/v1/users');
/* @var $response \Illuminate\Http\JsonResponse */
$response
->assertStatus(200)
->assertJson(['ok' => true, ]);
}
这也很好用。但是,这里使用了UserService
的普通绑定,我想在这里放置一个dummy/mock。
我想我需要将我的UserService
更改为一个接口,这很容易,但我不确定如何告诉底层测试系统我希望它运行我的控制器,但使用非标准服务。在研究这个问题时,我看到App::bind()
出现在Stack Overflow的答案中,但是App
并没有自动出现在artisan生成的测试中,所以感觉就像抓住了救命稻草。
我如何示例化一个虚拟服务,然后在测试时将其发送到Laravel,这样它就不会使用标准的ServiceProvider了?
3条答案
按热度按时间hfyxw5xn1#
最明显的方法是在
setUp()
中重新绑定实现。创建一个新的
UserTestCase
(或编辑Laravel提供的)并添加:在
register()
方法中基于环境有条件地注册提供程序(将其放入AppServiceProvider.php或您为此任务指定的任何其他提供程序-ConditionalLoaderServiceProvider.php或其他)注意:缺点是 list 的提供者在两个地方,一个在config/app.php,一个在AppServiceProvider.php
hjqgdpho2#
啊哈,我找到了一个临时的解决办法。我会把它贴在这里,然后解释如何改进它。
这将注入一个DI绑定,这样就不需要启动默认的ServiceProvider。如果我向
$response
添加一些调试代码,如下所示:然后我得到这个输出:
这允许我创建一个在PHP周围画出边界的测试,并且不调用测试框来与用户系统交互。
接下来,我将研究控制器的构造函数是否可以从具体实现提示(
\App\Services\Users
)更改为接口,这样我的测试实现就不需要从真实的的实现扩展。bq3bfh9z3#
在Laravel“Feature”测试中,你可以使用以下方法来模拟(改变正常绑定):
那么你就不会从服务容器中得到“YourService”的正常具体实现,你将得到一个模拟的实现。