12

I created a form request class and defined a bunch of rules. Now I would like to test these rules to see if the behaviour meets our expectations.

How could I write a test to accomplish that?

Many thanks in advance for your answers!

Update: more precisely, I would like to write a unit test that would check e.g. if a badly formatted email passes validation or not. The problem is that I don't know how to create a new instance of the Request with fake input in it.

kant312
  • 1,114
  • 1
  • 15
  • 28
  • 2
    there is a similar response here: http://stackoverflow.com/questions/36978147/unit-test-laravels-formrequest – Dov Benyomin Sohacheski May 08 '16 at 14:17
  • Possible duplicate of [Unit Test Laravel's FormRequest](https://stackoverflow.com/questions/36978147/unit-test-laravels-formrequest) – Yevgeniy Afanasyev Mar 28 '19 at 02:32
  • 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:33

3 Answers3

22

The accepted answer tests both authorization and validation simultaneously. If you want to test these function separately then you can do this:

test rules():

$attributes = ['aa' => 'asd'];
$request = new MyRequest();
$rules = $request->rules();
$validator = Validator::make($attributes, $rules);
$fails = $validator->fails();
$this->assertEquals(false, $fails);

test authorize():

$user = factory(User::class)->create();
$this->actingAs($user);
$request = new MyRequest();
$request->setContainer($this->app);
$attributes = ['aa' => 'asd'];
$request->initialize([], $attributes);
$this->app->instance('request', $request);
$authorized = $request->authorize();
$this->assertEquals(true, $authorized);

You should create some helper methods in base class to keep the tests DRY.

Martins Balodis
  • 1,999
  • 1
  • 17
  • 18
  • Depending on how complex your validation logic is (for instance, if you're assembling the `rules` array via code in your `Request` class), you'll want to assign your `$attributes` array to your custom `Request` class by adding this line after you create your `Request` object: `$request->replace($attributes);` – tmountjr Sep 19 '16 at 14:21
  • I'm having trouble understanding how your import `Validator` in a unit test. It's a facade class, right? – Zac Sep 26 '17 at 21:43
  • @Zac: Yeah you are right. You need to import Validator from Illuminate\Support\Facades\Validator. – Marco Dec 24 '17 at 21:43
2

You need to have your form request class in the controller function, for example

public function store(MyRequest $request)

Now create HTML form and try to fill it with different values. If validation fails then you will get messages in session, if it succeeds then you get into the controller function.

When Unit testing then call the url and add the values for testing as array. Laravel doc says it can be done as

$response = $this->call($method, $uri, $parameters, $cookies, $files, $server, $content);
Margus Pala
  • 8,433
  • 8
  • 42
  • 52
  • Hi and thanks for your answer! It's not really what I had in mind though :s I think my question was written rather poorly so I updated it. What I am trying to do is write a unit test to check if the validation rules I wrote are correct. – kant312 Apr 22 '15 at 12:32
  • Improved my answer also – Margus Pala Apr 22 '15 at 12:40
  • 8
    This seems a little contrived. Shouldn't you focus solely on the Request object and not be dependent on URIs, cookies, etc? – Dov Benyomin Sohacheski May 02 '16 at 05:25
  • @DovBenyominSohacheski though the approach is "valid", it is definitely not best practices. As you said, when unit testing everything apart from the class/function being tested should be mocked/stubbed – chesscov77 Jul 16 '17 at 17:38
  • @Juan check this link for a different solution: https://stackoverflow.com/a/37096837/5058871 – Dov Benyomin Sohacheski Jul 18 '17 at 01:18
2

Here's a full example of testing validation:

use App\Http\Requests\PostRequest;
use Illuminate\Routing\Redirector;
use Illuminate\Validation\ValidationException;

class PostRequestTest extends TestCase
{
    protected function newTestRequest($data = [])
    {
        $request = new PostRequest();

        $request->initialize($data);

        return $request
            ->setContainer($this->app)
            ->setRedirector($this->app->make(Redirector::class));
    }

    public function testValidationFailsWhenEmptyTitleIsGiven()
    {
        $this->expectException(ValidationException::class);

        $this->newTestRequest(['title' => ''])->validateWhenResolved();
    }
}
Steve Bauman
  • 8,165
  • 7
  • 40
  • 56