How to test POST routes in Laravel

2020-07-02 14:27发布

I'm doing the following to test a POST call to Laravel. I'm expecting that POST to questions, in accordance with my routes, will be dispatches as the store action method. This works in the browser.

My test:

public function setUp()
    {   
        parent::setUp();

        Session::start();
    }

    public function testStoreAction()
    {
        $response = $this->call('POST', 'questions', array(
            '_token' => csrf_token(),
        ));

        $this->assertRedirectedTo('questions');
    }

However, I tells me that the redirect doesn't match. Also, I can see that it isn't going to the store action method at all. I want to know what action method it is going to, and why it isn't going to the store method (if I look at route:list I can see there is a POST questions/ route that should go to questions.store; this also works in the browser, but not in my tests). Also, am I writing the call correctly for this resource? I added the token here as it was throwing an exception as it should, in some tests I will let the token check pass.

5条回答
forever°为你锁心
2楼-- · 2020-07-02 14:35

The most recommended way to test your routes is to check for 200 response. This is very helpful when you have multiple tests, like you are checking all of your post routes at once.

To do so, just use:

public function testStoreAction()
{
    $response = $this->call('POST', 'questions', array(
        '_token' => csrf_token(),
    ));

    $this->assertEquals(200, $response->getStatusCode());
}
查看更多
一夜七次
3楼-- · 2020-07-02 14:45

You could try this:

public function testStoreAction()
{
    Session::start();
    $response = $this->call('POST', 'questions', array(
        '_token' => csrf_token(),
    ));
    $this->assertEquals(302, $response->getStatusCode());
    $this->assertRedirectedTo('questions');
}
查看更多
家丑人穷心不美
4楼-- · 2020-07-02 14:46

Laravel Unit cases without middleware

    use WithoutMiddleware;

    protected $candidate = false;

    public function setUp(): void
    {
        parent::setUp();        

        $this->candidate = new Candidate();
    }   

    /** @test */
    public function it_can_get_job_list()
    {
        $this->actingAs($this->user, 'api');

        $response = $this->candidate->getJobsList();

        $this->assertNotNull($response);

        $this->assertArrayHasKey('data', $response->toArray());

        $this->assertNotEmpty($response);

        $this->assertInternalType('object', $response);
    }

查看更多
聊天终结者
5楼-- · 2020-07-02 14:53

I use

$response->assertSessionHasErrors(['key'=>'error-message']);

in order to assert validation works. But to use this, you must start from the page that is going to send the post request. Like this:

$user = User::where('name','Ahmad')->first(); //you can use factory. I never use factory while testing because it is slow. I only use factory to feed my database and migrate to make all my test faster.
$this->actingAs($user)->get('/user/create'); //This part is missing from most who get errors "key errors is missing"
$response = $this->post('/user/store', [
                '_token' => csrf_token()
            ]);
//If you use custom error message, you can add as array value as below.
$response->assertSessionHasErrors(['name' => 'Name is required. Cannot be empty']);
$response->assertSessionHasErrors(['email' => 'Email is required. Make sure key in correct email']);

Then if you want to test that the errors also being displayed correctly back. Run again above test with some changes as per below:

$this->actingAs($user)->get('/user/create'); 
$response = $this->followingRedirects()->post('/user/store', [
                '_token' => csrf_token()
            ]); //Add followingRedirects()
$response->assertSeeText('Name is required. Cannot be empty');
$response->assertSeeText('Email is required. Make sure key in correct email');

My guess is that if you dont start with the page to show the error, (the create / update page where you put the form), chain of session during the process will miss some important keys.

查看更多
We Are One
6楼-- · 2020-07-02 15:00

I was getting a TokenMismatchException and this fixed it, maybe it helps you too

public function testStoreAction()
{
    $response = $this->withSession(['_token' => 'covfefe'])
        ->post('questions', [
            '_token' => 'covfefe',
        ));

    $this->assertRedirectedTo('questions');
}
查看更多
登录 后发表回答