使用 Laravel 模型绑定模拟控制器测试
Posted
技术标签:
【中文标题】使用 Laravel 模型绑定模拟控制器测试【英文标题】:Mocking in controller tests with Laravel model binding 【发布时间】:2014-06-30 18:52:26 【问题描述】:我在我的路由中使用模型绑定将模型传递给我的控制器操作,并希望能够编写测试。如果测试不需要命中数据库,那就更好了。
在本例中使用用户名绑定模型,然后在路由的定义中使用。
// 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 Illuminate\Database\Eloquent\Builder given
我也希望能够使用 return User::firstByAttribtues($value);
,但 Mockery 不允许我模拟受保护的方法 - 有什么办法可以解决这个问题吗?
【问题讨论】:
【参考方案1】:我不得不翻遍 Mockery 的源代码才能找到这个,但你看过 shouldAllowMockingProtectedMethods 吗?
即模拟 foo 类并允许模拟受保护的方法:
$bar = \Mockery::mock('foo')->shouldAllowMockingProtectedMethods();
// now set your expectations up
然后从那里继续前进。
【讨论】:
【参考方案2】:不知道为什么您没有收到像调用了意外方法“firstOrFail”这样的错误。但是,乍一看,我认为问题在于您在 routes.php 中定义的模型路由也调用了 firstOrFail 方法。
所以,您的测试应该如下所示:
public function testShowPage()
$stubQuery = \Mockery::mock('Illuminate\Database\Eloquent\Builder');
$this->mock->shouldReceive('whereSlug')->once()->andReturn($stubQuery);
$stubQuery->shouldReceive('firstOrFail')->andReturn($this->mock);
$this->action('GET', 'UsersController@show');
$this->assertResponseOk();
$this->assertViewHas('user');
【讨论】:
以上是关于使用 Laravel 模型绑定模拟控制器测试的主要内容,如果未能解决你的问题,请参考以下文章
在 PHPUnit 中调用路由时如何在 Laravel 8 中模拟 Eloquent 模型