我在我的路由中使用模型绑定来将模型传递到我的控制器动作中,并希望能够编写测试。如果测试不需要访问数据库,则更可取。
在本例中使用用户名绑定模型,然后在路由定义中使用。
// routes.php
Route::model('user', function($value, $route)
{
return User::whereUsername($value)->firstOrFail();
});
Route::get('users/{user}', 'UsersController@show');
在我的控制器中,绑定的用户被传递给动作。
// UsersController.php
function show(User $user)
{
return View::make('users.show', compact('user');
}
现在,在我的测试中,我试图模仿用户。
// UsersControllerTest.php
public function setUp()
{
parent::setUp();
$this->mock = Mockery::mock('Eloquent', 'User');
$this->app->instance('User', $this->mock);
}
public function testShowPage()
{
$this->mock->shouldReceive('whereSlug')->once()->andReturn($this->mock);
$this->action('GET', 'UsersController@show');
$this->assertResponseOk();
$this->assertViewHas('user');
}
运行此测试时,我得到以下错误:
ErrorException: Argument 1 passed to UsersController::show() must be an instance of User, instance of IlluminateDatabaseEloquentBuilder given
我也想能够使用return User::firstByAttribtues($value);
,但嘲弄不会让我嘲笑一个受保护的方法-有什么办法我可以绕过这个吗?
我不得不挖掘mock的源代码来找到这个,但是您看过shouldAllowMockingProtectedMethods吗?
例如,模拟类foo并允许模拟受保护的方法:
$bar = Mockery::mock('foo')->shouldAllowMockingProtectedMethods();
// now set your expectations up
然后从那里继续
不知道为什么你没有得到一个错误像意外的方法"firstOrFail"调用。但是,乍一看,我认为问题在于你在routes.php中定义的模型路由也调用了firstOrFail方法。
所以,你的测试应该看起来像这样:public function testShowPage()
{
$stubQuery = Mockery::mock('IlluminateDatabaseEloquentBuilder');
$this->mock->shouldReceive('whereSlug')->once()->andReturn($stubQuery);
$stubQuery->shouldReceive('firstOrFail')->andReturn($this->mock);
$this->action('GET', 'UsersController@show');
$this->assertResponseOk();
$this->assertViewHas('user');
}