1

I'm trying to write some tests for my forms in order to confirm the validators retrieve the expected errors when required. The form only has 3 fields: name, discount and expiration and the validator looks like this:

$this->validate($request, [
    'name'          => 'required',
    'discount'      => 'required|numeric|between:1,100',
    'expiration'    => 'required|date_format:d/m/Y',
]);

That works fine both when submitting the form and when running the tests with phpunit using the following code:

/**
 * Discount must be numeric check
 */
$response = $this->post(route('offer.create'), [
    'name'          => $faker->sentence(4),
    'discount'      => 'asdasd',
    'expiration'    => $faker->dateTimeBetween('+1 days', '+5 months')
]);

// Check errors returned
$response->assertSessionHasErrors(['discount']);

Since discount is not numeric it throws the expected error and everybody is happy.

Now, if I want to add a new rule to make sure that the expiration is equal or greater to today I add the after:yesterdayrule leaving the validator like:

$this->validate($request, [
    'name'          => 'required',
    'discount'      => 'required|numeric|between:1,100',
    'expiration'    => 'required|date_format:d/m/Y|after:yesterday',
]);

That works fine when submitting the form. I get the error saying the discount is not numeric, but when testing with phpunit it doesn't get the error as expected:

1) Tests\Feature\CreateSpecialOfferTest::testCreateSpecialOffer
Session missing error: expiration
Failed asserting that false is true.

Why adding this new validation rule to expirationgenerates a false validation in discount? Is this a bug in the validator or am I missing something?

Also:

1 - is there a better way to test form validators?

2 - is there an assert that is the opposite of assertSessionHasErrors() to check a certain error is NOT been thrown?

AngelGris
  • 813
  • 1
  • 9
  • 25
  • Friends, please, make the unit-test properly, after all, it is not only rules you are testing here, the validationData and withValidator functions may be there too. [here is my answer](https://stackoverflow.com/questions/36978147/unit-test-laravels-formrequest/55389319#55389319) – Yevgeniy Afanasyev Mar 28 '19 at 02:38
  • Possible duplicate of [Unit Test Laravel's FormRequest](https://stackoverflow.com/questions/36978147/unit-test-laravels-formrequest) – Yevgeniy Afanasyev Mar 28 '19 at 02:39

1 Answers1

0

If you see this kind of errors in PHPUnit: Failed asserting that false is true., you can add the 'disableExceptionHandling' function to tests/TestCase.php:

<?php

namespace Tests;

use Exception;
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 disableExceptionHandling()
    {
        // Disable Laravel's default exception handling
        // and allow exceptions to bubble up the stack
        $this->app->instance(ExceptionHandler::class, new class extends Handler {
            public function __construct() {}
            public function report(Exception $exception) {}
            public function render($request, Exception $exception)
            {
                throw $exception;
            }
        });
    }
}

In your test you call it like this:

    <?php    
    /** @test */
    public function your_test_function()
    {

        $this->disableExceptionHandling();
    }

Now, the full output of the error and stacktrace will be shown in the PHPUnit console.

DelphiLynx
  • 911
  • 1
  • 16
  • 41
  • NOTICE: at later version of Laravel you can use $this->withoutExceptionHandling() without writing any code. – Michiel Dec 05 '19 at 13:43