使用Laravel模型绑定模拟控制器测试

时间:2014-05-13 07:45:17

标签: php laravel phpunit mockery

我在我的路线中使用模型绑定将模型传递到我的控制器操作中,并希望能够编写测试。如果测试不需要访问数据库,那将是更可取的。

在此示例中使用用户名绑定模型,然后在路径定义中使用。

// 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不会让我嘲笑一个受保护的方法 - 有什么方法可以解决这个问题吗?

2 个答案:

答案 0 :(得分:1)

我不得不通过Mockery的源代码来找到这个,但是你看过shouldAllowMockingProtectedMethods吗?

即,模拟类foo并允许模拟受保护的方法:

$bar = \Mockery::mock('foo')->shouldAllowMockingProtectedMethods();
// now set your expectations up

然后继续从那里开始。

答案 1 :(得分:0)

不确定为什么你没有像意外的方法那样得到错误" 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');
}