Correct way to seed and delete data in the database for Laravel testing?

Viewed 5237

I am new to Laravel tests, and i am currently building my tests so they use certain data in my database to check if an HTTP request did the appropriate job. I am trying to figure out how i can "seed" data into my database before i run my tests but also delete this data after all the tests are complete (either succeed of failed, should get deleted anyway).

I tried to understand how to do it correctly reading some articles in the internet but just couldn't find the right solution for me.

I know that in node.js the Mocha tests has a "beforeEach" to manipulate data before every test, is there a similar option in PHP Laravel?

2 Answers

With laravel version greater than 5.5 you can use the RefreshDatabase trait within your test which will reset your database after test have been run. All you will have to do is to add it at the top of your test like bellow

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;

class YourModelNameTest extends TestCase
{
    use RefreshDatabase;


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

        // This will run all your migration
        Artisan::call('migrate');

        // This will seed your database
        Artisan::call('db:seed');

        // If you wan to seed a specific table
        Artisan::call('db:seed', ['--class' => 'TableNameSeeder ', '--database' => 'testing']);
    }

}

The RefreshDatabase trait have define refreshDatabase which migrate the database before and after each test. you can see the code here

RefreshDatabse refreshDatabase

While Yves answer should work (separate database), i have found a set of methods that can help achieving what i needed: "setUp" and "tearDown".

the "setUp" method will do something before the set of tests will run (the test class) and "tearDown" will do something after all of those tests were executed.

I'm attaching my test class here for an example of how i used those:

<?php

namespace Tests\Feature;

use App\User;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;

class UserTest extends TestCase
{
    private $token;

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

        $userData = [
            'email' => 'mytestemail@email.com',
            'password' => '123456'
        ];

        $response = json_decode($this->post('/register', $userData)->baseResponse->getContent());

        $this->token = $response->token;
    }
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testRegister()
    {
        $validData = [
            'email' => 'testrerere@email.com',
            'password' => '123456'
        ];

        $invalidEmail = [
            'email' => 'not_a_real_email',
            'password' => '123456'
        ];

        $invalidPassword = [
            'email' => 'test2@email.com',
            'password' => '12'
        ];

        $emptyData = [];

        $goodResponse = $this->post('/register', $validData);

        $goodResponse->assertStatus(201);
        $goodResponse->assertJsonStructure(['token']);

        User::where('email', 'testrerere@email.com')->delete();

        $invalidEmailResponse = $this->post('/register', $invalidEmail);
        $invalidEmailResponse->assertStatus(400);

        $invalidPasswordResponse = $this->post('/register', $invalidPassword);
        $invalidPasswordResponse->assertStatus(400);

        $emptyDataResponse = $this->post('/register', $emptyData);
        $emptyDataResponse->assertStatus(400);
    }

    public function testToken()
    {
        $validData = [
            'email' => 'mytestemail@email.com',
            'password' => '123456'
        ];

        $invalidData = [
            'email' => 'nonexistingemail@test.com',
            'password' => '123456'
        ];

        $validDataResponse = $this->post('/token', $validData);
        $validDataResponse->assertStatus(200);
        $validDataResponse->assertJsonStructure(['token']);

        $invalidDataResponse = $this->post('/token', $invalidData);
        $invalidDataResponse->assertStatus(400);
    }

    //get an account object based on a token
    public function testAccount()
    {
        $goodResponse = $this->withHeaders([
            'Authorization' => 'Bearer ' . $this->token,
        ])->json('GET', '/account');

        $goodResponse
            ->assertStatus(200)
            ->assertJsonStructure([
                'user',
            ]);

        //altering the token to get an invalid token error
        $badResponse = $this->withHeaders([
            'Authorization' => 'Bearer L' . $this->token,
        ])->json('GET', '/account');

//        print_r($badResponse->baseResponse->getContent());

        $badResponse->assertJson(['status' => 'Token is Invalid']);
    }

    public function tearDown()
    {
        User::where('email', 'mytestemail@email.com')->delete();
        User::where('email', 'testrerere@email.com')->delete();

        parent::tearDown();
    }
}
Related