Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/244.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 什么';在Laravel中测试控制器的正确方法是什么?_Php_Unit Testing_Laravel_Mockery - Fatal编程技术网

Php 什么';在Laravel中测试控制器的正确方法是什么?

Php 什么';在Laravel中测试控制器的正确方法是什么?,php,unit-testing,laravel,mockery,Php,Unit Testing,Laravel,Mockery,我正在重写现有的Laravel4应用程序,以确保有足够的测试。长话短说,我已经用TDD方法重写了我的AccountController类,我有点头疼 考虑以下呈现包含用户列表的页面的方法: public function getIndex() { // build the view // return \View::make('account.list-users') ->with('users', \Sentry::getUserProvider(

我正在重写现有的Laravel4应用程序,以确保有足够的测试。长话短说,我已经用TDD方法重写了我的
AccountController
类,我有点头疼

考虑以下呈现包含用户列表的页面的方法:

public function getIndex()
{
    // build the view
    //
    return \View::make('account.list-users')
        ->with('users', \Sentry::getUserProvider()->findAll());
}
我正在使用Smarty呈现我的视图,并使用Sentry进行身份验证

现在,我想写一些如下的测试:

public function test_getIndex()
{
    // arrange
    //

    // set up some mocks here...


    // act
    //
    $response = $this->client->request("GET", "/list-users");


    // assert
    //

    // test for <table class="table">
    $this->assertFalse($response->filter("table.table")==null, "table not found");

    // test for some <a> tags for the "update" buttons
    $element = $response->filter("td a")->first()->extract(array("href", "class", "_text"));
    $this->assertTrue(strstr($element[0][0],"/my-update-url")!="");
    $this->assertTrue(strstr($element[0][1],"btn btn-xs btn-success")!="");
    $this->assertTrue(strstr($element[0][2],"Active")!="");

    // test for some other markup...

}
如果我采用这种方法,测试会简单得多,我只测试实际在控制器方法中的代码,但我并没有真正测试调用该路由所涉及的所有内容(这可能是件好事,也可能不是,我不确定),我担心我得不到足够的覆盖

那么,最好的方法是什么:(A)、(B)还是别的

编辑 对于我的控制器方法的测试,我有相当多的困惑,下面@TheShift Exchange的回答和评论更清楚地说明了这一点。作为编辑,我将在这里尝试解决这个问题,因为它给了我更多的空间来讨论这个问题

考虑下面答案中给出的第二个例子:

public function testMethod()
{
    $this->call('GET', '/list-users');

    $this->assertViewHas('users', \Sentry::getUserProvider()->findAll());
}
如果我运行这个测试,它会工作,但它会访问数据库,我试图通过模拟一些东西来避免访问数据库

所以,我可以稍微扩展一下这个测试:

public function testMethod()
{
    \Sentry::shouldReceive("getUserProvider")
        ->once()
        ->andReturn($userProvider);
    // plus a mock of the UserProvider class,...


    $this->call('GET', '/list-users');

    $this->assertViewHas('users', \Sentry::getUserProvider()->findAll());
}
这个测试将不起作用,因为除了controller方法所需的mock之外,我还需要在我的View composer中对代码进行mock。此代码包括,
$currentUser=\Sentry::getUser()
(用户名显示在我的应用程序页面的右上角)

因此,代码实际上变成:

public function testMethod()
{
    \Sentry::shouldReceive("getUserProvider")
        ->once()
        ->andReturn($userProvider);
    // plus a mock of the UserProvider class,...

    // plus a mock of ThisClass

    // and a mock of ThatClass

    // and a mock of SomeOtherClass

    // etc.

    // etc.

    $this->call('GET', '/list-users');

    $this->assertViewHas('users', \Sentry::getUserProvider()->findAll());
}
它很快就失控了

这对我来说意味着我做错了什么,但我不确定是什么。我怀疑这个问题源于我不确定我到底在测试什么

因此,在所有这些之后,问题变成了:

当我测试控制器的方法时,我真正想要测试的是什么

  • 控制器方法中的代码?或者

  • 从请求到响应的整个过程

  • 我想测试的是第一项-只是控制器方法中的代码。我的问题中的示例非常简单,但我确实有一些控制器方法,可以根据用户输入进行表单验证或重定向,我想测试这些代码


    也许,与其通过
    $this->call()
    测试代码,我需要直接调用控制器方法?

    作为Laravel框架的一部分。这些帮助程序中包括视图测试帮助程序:

    断言视图有一些数据

    public function testMethod()
    {
        $this->call('GET', '/');
    
        $this->assertViewHas('name');
        $this->assertViewHas('age', $value);
    }
    
    这样您就可以执行如下操作:

    public function testMethod()
    {
        \Sentry::shouldReceive("getUserProvider")
        ->once()
        ->andReturn('foo');
    
        $this->call('GET', '/');
    
        $this->assertViewHas('users', 'foo');
    }
    

    是的,我知道这些断言,但我的问题更多的是关于测试的设置,而不是最后的断言。我不明白-你想测试什么?如果视图获得了用户,那么您还需要测试什么?似乎我已经用两行代码而不是40行代码测试了你的控制器功能?谢谢你的评论-你帮助我思考了更多的问题&我编辑了这个问题以(我希望)澄清它。我认为你试图在一个功能中测试太多了。如果控制器响应正确的路由并使用正确的数据调用正确的视图,那么控制器测试就是正确的。就这样。它不应该测试视图本身。同时,只需为视图生成器编写另一个单独的测试——它调用所有正确的变量。好的,我明白了。这是有道理的——我一直在嘲笑这些东西,因为我试图避免数据库访问(因为我认为这很重要)——这在这些测试中不重要吗?
    public function testMethod()
    {
        \Sentry::shouldReceive("getUserProvider")
        ->once()
        ->andReturn('foo');
    
        $this->call('GET', '/');
    
        $this->assertViewHas('users', 'foo');
    }