2

I want to test the response when I try to send invalid data to the API.

/** @test */
public function request_schedule_with_invalid_bdate()
{
    $response = $this->json('GET', '/api/schedule', [
      'bdate' => 'thisaintadate',
    ]);

    $response->assertStatus(422);
}

According to the documentation it should return a 422

If the validation rules pass, your code will keep executing normally; however, if validation fails, an exception will be thrown and the proper error response will automatically be sent back to the user. In the case of a traditional HTTP request, a redirect response will be generated, while a JSON response will be sent for AJAX requests.

Also,

When using the validate method during an AJAX request, Laravel ... generates a JSON response containing all of the validation errors. This JSON response will be sent with a 422 HTTP status code.

It sounds like Laravel should automatically handle the exception thrown and proceed with sending the response.

However, running this in PHPUnit would just cause an error.

There was 1 error:

1) Tests\Feature\ScheduleTest::request_schedule_with_invalid_bdate
Illuminate\Validation\ValidationException: The given data was invalid.

I read this question but using $this->expectException(...); will make the test pass but not run my assertions. If I assert the status to be something else other than 422, it will still pass.

My controller has this:

public function show(Request $request) 
{
  $attributes = $request->validate([
    'bdate' => 'required|date'
  ]);

  return ['data' => "It's valid."]
}

Here is my ExceptionHandler class (as requested by Martin H.) This is just what's out of the box. I haven't touched this class yet.

<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;

class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that are not reported.
     *
     * @var array
     */
    protected $dontReport = [
        //
    ];

    /**
     * A list of the inputs that are never flashed for validation exceptions.
     *
     * @var array
     */
    protected $dontFlash = [
        'password',
        'password_confirmation',
    ];

    /**
     * Report or log an exception.
     *
     * @param  \Exception  $exception
     * @return void
     */
    public function report(Exception $exception)
    {
        parent::report($exception);
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Exception  $exception
     * @return \Illuminate\Http\Response
     */
    public function render($request, Exception $exception)
    {
        return parent::render($request, $exception);
    }
}

I have confirmed the following:

  • Laravel Framework 5.7.21 (php artisan --version output)
  • It runs the appropriate code/controller based on the stack trace:

    .../vendor/laravel/framework/src/Illuminate/Validation/Validator.php:315 .../vendor/laravel/framework/src/Illuminate/Validation/Factory.php:136 .../vendor/laravel/framework/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php:53 .../vendor/laravel/framework/src/Illuminate/Support/Traits/Macroable.php:108 .../app/Http/Controllers/MyController.php:35

What am I missing?

3
  • Can you post your exception handler class, i highly suggest within there is the fault
    – mrhn
    Commented Feb 18, 2019 at 23:10
  • @MartinHenriksen I added the ExceptionHandler class.
    – user11006952
    Commented Feb 18, 2019 at 23:18
  • I figured out why my test was crashing.
    – user11006952
    Commented Feb 18, 2019 at 23:28

1 Answer 1

3

I was having a problem with the ValidationException crashing my test because I disabled exception handling. I disabled exception handling so I can debug my tests better (ironic, I know) and I forgot that I did this.

class ... extends TestCase 
{
    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->withoutExceptionHandling();
    }

Removing $this->withoutExceptionHandling(); now allows me to do assertions on the response.

There was 1 failure:

1) Tests\Feature\ScheduleTest::request_schedule_with_invalid_bdate
Expected status code 200 but received 422.
Failed asserting that false is true.

Relevant links: - https://github.com/laravel/framework/issues/26013 - laravel phpunit withexceptionhandling