Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel 4 controller tests - ErrorException after too many $this->call() - why?

I'd greatly appreciate some help regarding a Laravel 4 issue I'm experiencing.

I'm testing controller routes, specifically a controller that is responsible for routing responses for a questionnaire. I'm testing scenarios such as: the user attempting to skip a question, the user requesting a question that doesn't exist... etc.

The tests that I've written for all scenarios up until now work as expected using PHPunit. The test I'm currently writing involves several $this->call() or $this->client->request() executions and that's where things break down. If I execute $this->call() or $this->client->request() too many times (2 or more to be specific) in a single test method I get an ErrorException in the terminal:

{"error":{"type":"ErrorException","message":"Undefined variable: header","file":"/Volumes/Dev HD/dmh/app/views/layouts/steps.php","line":1}}

If I reduce the quantity of $this->call() or $this->client->request() in the test method to one, things work, and no exception is shown. I've been using the following code:

Code

/**
 * 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');
}

Any ideas?

Do I need to reset something in order to make several calls? Is this bad practice for making several calls like this? Is there a better way to write this test? Any ideas would be greatly appreciated.

Thanks a bunch!

like image 959
dbrown428 Avatar asked Jul 07 '13 19:07

dbrown428


Video Answer


1 Answers

Probable Solution:

Use $this->client->restart() to start a new request.

Explanation/Detail:

OK so, here's the rabbit hole :D

  1. Laravel TestCase extends Illuminate\Foundation\Testing\TestCase
  2. Illuminate\Foundation\Testing\TestCase uses Illuminate\Foundation\Testing\Client to make the fake requests.
  3. Illuminate\Foundation\Testing\Client extends Symfony\Component\HttpKernel\Client
  4. Symfony\Component\HttpKernel\Client extends abstract class Symfony\Component\BrowserKit\ Client
  5. Abstract class Symfony\Component\BrowserKit\ Client has a method restart()

So, I believe in your case (I haven't personally tested this), you should be able to do the following:

/**
 * 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');
}

Note that the call() method is a proxy to using $this->client->request()

Hope that helps! Don't be afraid to dig into code inheritances to see if a convenience method exists to do what you need - changes are it often already exists :D

Improvement(?)

Note that these tests might lean more towards "integration tests" rather than "unit tests". Integration tests may be a better fit when used with continuous integration frameworks. See this question for some more info.

like image 198
fideloper Avatar answered Nov 02 '22 23:11

fideloper