【问题标题】:Laravel 4 controller tests - ErrorException after too many $this->call() - why?Laravel 4 控制器测试 - 太多 $this->call() 后出现 ErrorException - 为什么?
【发布时间】:2013-07-05 03:09:39
【问题描述】:

非常感谢有关我遇到的 Laravel 4 问题的一些帮助。

我正在测试控制器路由,特别是负责路由问卷响应的控制器。我正在测试以下场景:用户试图跳过一个问题,用户请求一个不存在的问题......等等。

到目前为止,我为所有场景编写的测试都使用 PHPunit 按预期工作。我目前正在编写的测试涉及多次$this->call()$this->client->request() 处决,这就是问题所在。如果我在单个测试方法中执行 $this->call()$this->client->request() 太多次(具体为 2 次或更多次),我会在终端中收到 ErrorException:

{"error":{"type":"ErrorException","message":"未定义变量:header","file":"/Volumes/Dev HD/dmh/app/views/layouts/steps.php ","行":1}}

如果我将测试方法中$this->call()$this->client->request() 的数量减少到一个,一切正常,并且没有显示异常。我一直在使用以下代码:

代码

/**
 * When the user skips questions they have not yet answered, the user 
 * should be redirected back to the first unanswered question.
 *
 * @return void
 */
public function testDiscoverSkipQuestions()
{
    // Get the first question.
    $domCrawler = $this->client->request('GET', 'style/discover');

    // Answer the first question
    $form = $domCrawler->selectButton("Next »")->form();
    $form['question_1'] = 'A:0';
    $response = $this->client->submit($form);
    $this->assertRedirectedTo('style/discover/2');

    // Get the 5th question.
    $this->call('GET', 'style/discover/5');
    // BROKEN

    // Expect to be redirected to the 2nd question.
    $this->assertRedirectedTo('style/discover/2');
    $this->assertSessionHas('attention');
}

有什么想法吗?

我是否需要重置某些内容才能拨打多个电话?像这样打几个电话是不好的做法吗?有没有更好的方法来编写这个测试?任何想法将不胜感激。

非常感谢!

【问题讨论】:

    标签: testing controller phpunit laravel laravel-4


    【解决方案1】:

    可能的解决方案:

    使用$this->client->restart() 发起新请求。

    解释/细节:

    好吧,这是兔子洞:D

    1. Laravel TestCase 扩展 Illuminate\Foundation\Testing\TestCase
    2. Illuminate\Foundation\Testing\TestCase 使用 Illuminate\Foundation\Testing\Client 发出虚假请求。
    3. Illuminate\Foundation\Testing\Client 扩展 Symfony\Component\HttpKernel\Client
    4. Symfony\Component\HttpKernel\Client 扩展抽象类 Symfony\Component\BrowserKit\ Client
    5. 抽象类Symfony\Component\BrowserKit\ Client有一个方法restart()

    所以,我相信你的情况(我没有亲自测试过),你应该能够做到以下几点:

    /**
     * When the user skips questions they have not yet answered, the user 
     * should be redirected back to the first unanswered question.
     *
     * @return void
     */
    public function testDiscoverSkipQuestions()
    {
        // Get the first question.
        $domCrawler = $this->client->request('GET', 'style/discover');
    
        // Answer the first question
        $form = $domCrawler->selectButton("Next »")->form();
        $form['question_1'] = 'A:0';
        $response = $this->client->submit($form);
        $this->assertRedirectedTo('style/discover/2');
    
        // ******** Restart for new request ********
        $this->client->restart();
    
        // Get the 5th question.
        $this->call('GET', 'style/discover/5');
        // ******** SHOULD NOW WORK - call() is a proxy to $this->client->request(); ********
    
        // Expect to be redirected to the 2nd question.
        $this->assertRedirectedTo('style/discover/2');
        $this->assertSessionHas('attention');
    }
    

    注意 call() 方法是a proxy to using $this->client->request()

    希望对您有所帮助!不要害怕深入研究代码继承,看看是否存在一种方便的方法来做你需要的事情 - 改变它通常已经存在:D

    改进(?)

    请注意,这些测试可能更倾向于“集成测试”而不是“单元测试”。与持续集成框架一起使用时,集成测试可能更合适。请参阅this question 了解更多信息。

    【讨论】:

    • 非常感谢,效果很好。另外,我很欣赏关于“集成测试”的正确方向的推动。谢谢!
    • 谢谢你,就像一个魅力。但是我仍然想知道为什么我们需要在连续请求之间在客户端上调用restart()。幕后究竟发生了什么导致所有麻烦?
    • @cafonso 您调用 restart 来启动一个新的 HTTP 请求,而不是添加到现有的请求上。 (HTTP 请求由一个 PHP 对象表示,该对象需要为新的 HTTP 请求重新创建)。这并不是一个真正的“问题”,而是准确地建模在这个正在测试的过程中有多个 HTTP 请求。希望这是有道理的!
    猜你喜欢
    • 2013-09-28
    • 2014-06-23
    • 2014-03-25
    • 1970-01-01
    • 1970-01-01
    • 2014-08-06
    • 2015-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多