Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling Laravel HttpException in Unit Testing

One of my test functions for unit testing in Laravel keeps erroring out. I'm trying to assert that requesting a specific page without certain conditions being met triggers a 403 FORBIDDEN error.

My test case function is this:

public function testNoAjaxCall() {

    $this->call('POST', 'xyz', array());

    $this->assertResponseStatus(403);

}

In the controller action this is routed to, I have this:

if(!Input::has('ajax') || Input::get('ajax') != 1) {

    // Drop all 'non-ajax' requests.
    App::abort(403, 'Normal POST requests to this page are forbidden. Please explicitly tell me you\'re using AJAX by passing ajax = 1.');

}

Running phpunit returns with the following:

1) RaceTest::testNoAjaxCall

Symfony\Component\HttpKernel\Exception\HttpException: Normal POST requests to this page are forbidden. Please explicitly tell me you're using AJAX by passing ajax = 1.

[path\to\laravel]\vendor\laravel\framework\src\Illuminate\Foundation\Application.php:875

[redacted stack trace]

[path\to\laravel]\vendor\symfony\http-kernel\Symfony\Component\HttpKernel\Client.php:81

[path\to\laravel]\vendor\symfony\browser-kit\Symfony\Component\BrowserKit\Client.php:325

[path\to\laravel]\vendor\laravel\framework\src\Illuminate\Foundation\Testing\TestCase.php:74

[path\to\laravel]\app\tests[testFileName].php:176

FAILURES!

Tests: 6, Assertions: 17, Errors: 1.

Of course the stack trace points back to $this->call(..); and App::abort(..)

I have a HttpException error handler in my app/start/global.php file, which works when triggering it outside of unit testing (e.g. making a POST request directly to the tested URL), but unit testing doesn't seem to correctly catch the exception or even reach the assert call.

What am I missing?

like image 463
Sean Avatar asked Feb 04 '14 14:02

Sean


People also ask

What is exception handling in Laravel?

Reporting ExceptionsAll exceptions are handled by the App\Exceptions\Handler class. This class contains a register method where you may register custom exception reporting and rendering callbacks.

How do you do error reporting in Laravel?

Through your config/app. php , set 'debug' => env('APP_DEBUG', false), to true . Or in a better way, check out your . env file and make sure to set the debug element to true.


2 Answers

http://phpunit.de/manual/3.7/en/appendixes.annotations.html#appendixes.annotations.expectedException should already explain it.

/**
 * @expectedException \Symfony\Component\HttpKernel\Exception\HttpException
 * @expectedExceptionMessage Normal POST requests to this page are forbidden. Please explicitly tell me you\'re using AJAX by passing ajax = 1.
 */
public function testNoAjaxCall() {

    $this->call('POST', 'xyz', array());

}
like image 113
crynobone Avatar answered Oct 17 '22 03:10

crynobone


As of now, the best way I have found to assert HttpException status codes can be found in sirbarrence's work around at https://github.com/laravel/framework/issues/3979

TestCase.php:

public function assertHTTPExceptionStatus($expectedStatusCode, Closure $codeThatShouldThrow)
{
    try 
    {
        $codeThatShouldThrow($this);

        $this->assertFalse(true, "An HttpException should have been thrown by the provided Closure.");
    } 
    catch (\Symfony\Component\HttpKernel\Exception\HttpException $e) 
    {
        // assertResponseStatus() won't work because the response object is null
        $this->assertEquals(
            $expectedStatusCode,
            $e->getStatusCode(),
            sprintf("Expected an HTTP status of %d but got %d.", $expectedStatusCode, $e->getStatusCode())
        );
    }
}

Usage:

public function testGetFailsWith403()
{
    $this->assertHTTPExceptionStatus(403, function ($_this)
    {
        $_this->call('GET', '/thing-that-should-fail');
    });
}
like image 45
Matt Votsikas Avatar answered Oct 17 '22 03:10

Matt Votsikas