Laravel: How to enable stacktrace error on PhpUnit
Asked Answered
P

3

25

I have a fresh installation of laravel 5.4

I've tried to modify the default test just to see a failing test.

tests/ExampleTest.php

class ExampleTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testBasicTest()
    {
        $response = $this->get('/ooops');

        $response->assertStatus(200);
    }
}

I was expecting to see more detailed error like no route has been found or defined etc, but instead just this error saying

Time: 1.13 seconds, Memory: 8.00MB

There was 1 failure:

1) Tests\Feature\ExampleTest::testBasicTest
Expected status code 200 but received 404.
Failed asserting that false is true.

/var/www/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestResponse.php:51
/var/www/tests/Feature/ExampleTest.php:21

Its really hard to do TDD without meaningful error (yeah I know 404 in this case is enough, but most of the time its not the case).

Is there a way to enable the stacktrace the same as the one displayed on the browser? Or at least closer to that one so that I know what's the next step I should do.

Thanks in advance.

Proffer answered 30/1, 2017 at 21:22 Comment(0)
P
37

For Laravel 5.4 you can use disableExceptionHandling method presented by Adam Wathan in this gist (source code below)

Now if you run in your test:

$this->disableExceptionHandling();

you should get full info that will help you to find the problem.

For Laravel 5.5 and up you can use withoutExceptionHandling method that is built-in into Laravel

Source code of Adam Wathan's gist

<?php

namespace Tests;

use App\Exceptions\Handler;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication;

    protected function setUp()
    {
        /**
         * This disables the exception handling to display the stacktrace on the console
         * the same way as it shown on the browser
         */
        parent::setUp();
        $this->disableExceptionHandling();
    }

    protected function disableExceptionHandling()
    {
        $this->app->instance(ExceptionHandler::class, new class extends Handler {
            public function __construct() {}

            public function report(\Exception $e)
            {
                // no-op
            }

            public function render($request, \Exception $e) {
                throw $e;
            }
        });
    }
}
Pedigo answered 30/1, 2017 at 21:31 Comment(6)
thanks a lot, the stacktrace is showing now. It seems that I have to call it on every method. I've put it on the abstract TestCase::setUp method. Is there a recommended way of applying it on every test?Proffer
@JaimeSangcap In fact it's not, it should be rather used in my opinion as helper when you test for errors, but you should not have it when running real tests because it might change the result and your test will be wrong depending on your app, so just use it only as a helper that helps you debug errors in test and not as a part of testCas
yes you're right, and even without the disableExceptionHandling it produces meaningful errors as go. Thanks for pointing that out, that might saved me hours of hair pulling ;)Proffer
In Laravel 5.7 the method is $this->withoutExceptionHandling();Ropedancer
This works great for me, I am using Laravel 5.7, Thank you!Heppman
excellent answer, detailed and working - thanks!Pinpoint
V
19

If you happen to use Laravel 5.5 and up, you can use the built-in methods:

$this->withoutExceptionHandling();
$this->withExceptionHandling();

Either in your setUp method, or in your test method's. They are defined in the following trait.

For quick and dirty debugging, you can also use the dump method on the response object:

/** @test */
public function it_can_delete_an_attribute()
{
    $response = $this->json('DELETE', "/api/attributes/3");

    $response->dump()->assertStatus(200);

    $this->assertDatabaseMissing('table', [
        'id' => $id
    ]);

    ...
}

There is a laracast lesson that covers these details.

Valentin answered 13/9, 2018 at 14:18 Comment(1)
The $this->withoutExceptionHandling(); doesn't seem to work in Laravel 5.8. My code throws a 500 and just returns the Expected status code 200 but received 500.Bordiuk
P
1

To everyone implementing any of the solutions above but still not getting the exceptions: check if you don't use a try{}catch(){} block in your tested functions, as I did.

Of course, in that case, disabling the exception handler in the test won't give you the exception.

Polak answered 15/10, 2023 at 5:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.