【发布时间】:2015-08-05 02:41:08
【问题描述】:
首先,我知道docs 状态:
注意:你不应该模拟 Request 门面。相反,在运行测试时将所需的输入传递给 HTTP 帮助方法,例如 call 和 post。
但是这些测试更像是集成或功能,因为即使您正在测试控制器(SUT) ,你并没有将它与它的依赖关系解耦(Request 和其他人,稍后会详细介绍)。
所以,为了执行正确的TDD 循环,我正在做的是模拟Repository、Response 和Request(我有问题)。
我的测试如下所示:
public function test__it_shows_a_list_of_categories() {
$categories = [];
$this->repositoryMock->shouldReceive('getAll')
->withNoArgs()
->once()
->andReturn($categories);
Response::shouldReceive('view')
->once()
->with('categories.admin.index')
->andReturnSelf();
Response::shouldReceive('with')
->once()
->with('categories', $categories)
->andReturnSelf();
$this->sut->index();
// Assertions as mock expectations
}
这很好用,它们遵循 Arrange、Act、Assert 风格。
问题在于Request,如下所示:
public function test__it_stores_a_category() {
Redirect::shouldReceive('route')
->once()
->with('categories.admin.index')
->andReturnSelf();
Request::shouldReceive('only')
->once()
->with('name')
->andReturn(['name' => 'foo']);
$this->repositoryMock->shouldReceive('create')
->once()
->with(['name' => 'foo']);
// Laravel facades wont expose Mockery#getMock() so this is a hackz
// in order to pass mocked dependency to the controller's method
$this->sut->store(Request::getFacadeRoot());
// Assertions as mock expectations
}
如你所见,我嘲笑了Request::only('name') 电话。但是当我运行$ phpunit 时,出现以下错误:
BadMethodCallException: Method Mockery_3_Illuminate_Http_Request::setUserResolver() does not exist on this mock object
由于我没有从我的控制器直接调用setUserResolver(),这意味着它是由Request 的实现直接调用的。但为什么?我嘲笑了方法调用,它不应该调用任何依赖项。
我在这里做错了什么,为什么会收到此错误消息?
PS:作为奖励,我是否通过在 Laravel 框架上强制 TDD 和单元测试来寻找错误的方式,因为文档似乎是通过将依赖项和 SUT 之间的交互与 $this->call() 耦合来进行集成测试的?
【问题讨论】:
-
今天遇到了这个问题。相关:twitter.com/laravelphp/status/556568018864459776
-
更简单的选项:如果您的被测函数采用
Request参数,并且您只需要一个简单的“真实路由路径”请求,那么:您不需要mock一个请求,你可以创建一个请求从路由并传递它,像这样:$myRequest = Request::create('/path/that/I_want', 'GET'); $this->assertTrue(functionUnderTest($myRequest));
标签: unit-testing laravel laravel-5 tdd laravel-5.1