Done!

How to Specify a Separate Database for Unit Testing on Laravel 5


There are two ways of specifying separate database for unit test in Laravel.

Method 1

Step 1: Create New Test Database Connection on config/database.php as below:

return [
    ... 

    'default' => env('DB_CONNECTION', 'db'),    

    'connections' => [
        'sqlite_testing_db' => [
            'driver' => 'sqlite',
            'database' => storage_path().'/testing_database.sqlite',           
            'prefix' => '',
        ],

        /**************** OR ******************/
        
        'testing_db' => [
            'driver' => 'mysql',
            'host' => env('TEST_DB_HOST', 'localhost'),
            'database' => env('TEST_DB_DATABASE', 'forge'),
            'username' => env('TEST_DB_USERNAME', 'forge'),
            'password' => env('TEST_DB_PASSWORD', ''),
            'charset' => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix' => '',
            'strict' => false,
        ],

        /** Production or database DB **/
        'db' => [
            'driver' => 'mysql',
            'host' => env('TEST_DB_HOST', 'localhost'),
            'database' => env('TEST_DB_DATABASE', 'forge'),
            'username' => env('TEST_DB_USERNAME', 'forge'),
            'password' => env('TEST_DB_PASSWORD', ''),
            'charset' => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix' => '',
            'strict' => false,
        ],
    ],
];

Step 2: Specify the Database Credential on .env file

TEST_DB_HOST=localhost
TEST_DB_DATABASE=laravel
TEST_DB_USERNAME=root
TEST_DB_PASSWORD=rootwdp

Step 3: Specify test db conection to be used on phpunit.xml.

<env name="DB_CONNECTION" value="testing_db"/>
          OR Below If you prefer sqlite
<env name="DB_CONNECTION" value="sqlite_testing_db"/>                

Step 4: Migrate database to this new testing database - if you choose to use Database Transaction to Rollback insertion on the table.

php artisan migrate --database=testing_db

//If using sqlite
touch storage/testing_database.sqlite
php artisan migrate --database=sqlite_testing

Step 5: Now, the Unit test with Database Transaction looks like below:

<?php

use App\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;

class UserTest extends TestCase
{
    use DatabaseTransactions;

    /** @test */
    function it_test_user_can_be_saved()
    {
        factory(User::class, 2)->create();

        $users = User::all();

        $this->assertEquals(2, $users->count());
    }
}

//Run Php Unit
-> vendor/bin/phpunit --color tests/acceptance/model/UserTest.php

Note: If you prefer not to use Database Transaction, you can use setup and teardown method on TestCase.php class to migrate and rollback the database as below:

<?php

use Illuminate\Support\Facades\Artisan;

class TestCase extends Illuminate\Foundation\Testing\TestCase
{
    ...

    public function setUp()
    {
        parent::setUp();
        Artisan::call('migrate');
    }

    public function tearDown()
    {
        Artisan::call('migrate:reset');
        parent::tearDown();
    }
}

Method 2

Step 1: Create New Test Database Connection on Database/Config.php as below:

return [
    ... 

    'default' => env('DB_CONNECTION', 'db'),    

    'connections' => [
        'sqlite_testing_db' => [
            'driver' => 'sqlite',
            'database' => storage_path().'/testing_database.sqlite',           
            'prefix' => '',
        ],

        /**************** OR ******************/
        
        'testing_db' => [
            'driver' => 'mysql',
            'host' => env('TEST_DB_HOST', 'localhost'),
            'database' => env('TEST_DB_DATABASE', 'forge'),
            'username' => env('TEST_DB_USERNAME', 'forge'),
            'password' => env('TEST_DB_PASSWORD', ''),
            'charset' => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix' => '',
            'strict' => false,
        ],

        /** Production or database DB **/
        'db' => [
            'driver' => 'mysql',
            'host' => env('TEST_DB_HOST', 'localhost'),
            'database' => env('TEST_DB_DATABASE', 'forge'),
            'username' => env('TEST_DB_USERNAME', 'forge'),
            'password' => env('TEST_DB_PASSWORD', ''),
            'charset' => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix' => '',
            'strict' => false,
        ],
    ],
];

Step 2: Create .env.testing environment file on root

APP_ENV=testing

DB_CONNECTION=testing_db
//or
//DB_CONNECTION=sqlite_testing_db

TEST_DB_HOST=localhost
TEST_DB_DATABASE=laravel
TEST_DB_USERNAME=root
TEST_DB_PASSWORD=rootwdp

Step 3: Load .env.testing testing environment, and also set up PHP artisan to migrate and rollback the database on from the TestCase.php

<?php

use Illuminate\Support\Facades\Artisan;

class TestCase extends Illuminate\Foundation\Testing\TestCase
{
    public function createApplication()
    {
        $app = require __DIR__.'/../bootstrap/app.php';

        //Load .env.testing environment
        $app->loadEnvironmentFrom('.env.testing');

        $app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();

        return $app;
    }
    
    public function setUp()
    {
        parent::setUp();
        Artisan::call('migrate');
    }

    public function tearDown()
    {
        Artisan::call('migrate:reset');
        parent::tearDown();
    }
}

Step 4: Ensure file is create if sqlite database is selected to be used!

touch storage/testing_database.sqlite

Step 5: Unit Test Sample. No need to use Database Transaction as setup and teardown method calls migrate and rollback of database respectively.

<?php

use App\User;

class UserTest extends TestCase
{
    /** @test */
    function it_test_user_can_be_saved()
    {
        factory(User::class, 2)->create();

        $users = User::all();

        $this->assertEquals(2, $users->count());
    }
}

//Run Php Unit
-> vendor/bin/phpunit --color tests/acceptance/model/UserTest.php