How to specify a testing database in Laravel 5?

Published 2 years ago by mkudenko

I'm trying to write unit tests for my models and controllers. I know that Laravel sets the environment to "testing" by default, but I can't figure out where to specify the test database name so it's not version controlled.

I can change the database name in phpunit.xml, but that file is commited:

<env name="DB_DATABASE" value="test_db"/>

Ideally, I'd like it to work like the .env file. .env.test maybe, that is used for unit testing?

Any help and advice are appreciated.

Best Answer (As Selected By mkudenko)
mkudenko

Thank you @blackbird and @JoeDawson. I've switched from default PHPUnit to Codeception. Using Laravel5 module for specifying a testing .env file works perfectly.

Here's what I ended up using for my unit tests. Well, technically some of them are integration tests, since the database is used, but anyway.

Here's a snippet of my config/database.php file:

<?php

return [

    // other stuff

    'default' => env('DB_DEFAULT', 'mysql'),

    'connections' => [

        'sqlite_testing' => [
            'driver'   => 'sqlite',
            'database' => ':memory:',
            'prefix'   => '',
        ],

        'mysql' => [
        'driver'    => 'mysql',
        'host'      => env('DB_HOST', 'localhost'),
        'database'  => env('DB_DATABASE', 'forge'),
        'username'  => env('DB_USERNAME', 'forge'),
        'password'  => env('DB_PASSWORD', ''),
        'charset'   => 'utf8',
        'collation' => 'utf8_unicode_ci',
        'prefix'    => '',
            'strict'    => false,
        ],

    ],

    // other stuff

];

I'm using the sqlite database in memory which is a lot faster. You can't use it in functional or acceptance tests though.

And now a snippet of my tests/unit/TestCase.php. I set up the DB_DEFAULT variable which switches the database driver for each test. That way, I can run my unit/integration tests without having a separate .env.unit file.

<?php namespace UnitTests;

use Illuminate\Support\Facades\Artisan;

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

    /**
     * Creates the application.
     *
     * @return \Illuminate\Foundation\Application
     */
    public function createApplication()
    {
        putenv('DB_DEFAULT=sqlite_testing');

        $app = require __DIR__ . '/../../bootstrap/app.php';

        $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();
    }

}

Final note. As of this moment, running composer require "codeception/codeception:*" will get you the version 2.0.11. Running functional tests with Laravel 5 module will through a fatal error.

https://github.com/Codeception/Codeception/pull/1756

That will be fixed in 2.0.12, but for now you can install the latest dev version: composer require "codeception/codeception": "2.0.*@dev"

JoeDawson
bobbybouwmann

So I'm using codeception with php unit. Mine is pretty easy setup like this:

// .env
APP_ENV=local
APP_DEBUG=true
APP_KEY=some_random_key

DB_HOST=localhost
DB_DATABASE=laravel
DB_USERNAME=homestead
DB_PASSWORD=secret
// .env.testomg
APP_ENV=testing
APP_DEBUG=true
APP_KEY=some_random_key

// Notice the extra variable
// Notice as well that I use sqlite for testing, because it's faster and easier with that ;)
DB_DEFAULT=sqlite_testing 

In my config/database file I have this

return [

    // Other stuff

    'default' => env('DB_DEFAULT', 'mysql'),

    'connections' => [

        'sqlite_testing' => [
            'driver'        => 'sqlite',
            'database'  => storage_path() . '/testing.sqlite',
            'prefix'        => '',
        ],

        'mysql' => [
            'driver'    => 'mysql',
            'host'      => env('DB_HOST', 'localhost'),
            'database'  => env('DB_DATABASE', 'forge'),
            'username'  => env('DB_USERNAME', 'forge'),
            'password'  => env('DB_PASSWORD', ''),
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
            'strict'    => false,
        ],  

        // Other connections

    ];

    // Other stuff
];

Note: It's important that you create the testing.sqlite file in the storage folder!

If you use Codeception like I do you only have to specify the environment file in the suite.yml file like this:

// functional.suite.yml

class_name: FunctionalTester
modules:
    enabled: [Filesystem, FunctionalHelper, Laravel5]
    config:
        Laravel5:
            environment_file: .env.testing
mkudenko

Thank you @blackbird and @JoeDawson. I've switched from default PHPUnit to Codeception. Using Laravel5 module for specifying a testing .env file works perfectly.

Here's what I ended up using for my unit tests. Well, technically some of them are integration tests, since the database is used, but anyway.

Here's a snippet of my config/database.php file:

<?php

return [

    // other stuff

    'default' => env('DB_DEFAULT', 'mysql'),

    'connections' => [

        'sqlite_testing' => [
            'driver'   => 'sqlite',
            'database' => ':memory:',
            'prefix'   => '',
        ],

        'mysql' => [
        'driver'    => 'mysql',
        'host'      => env('DB_HOST', 'localhost'),
        'database'  => env('DB_DATABASE', 'forge'),
        'username'  => env('DB_USERNAME', 'forge'),
        'password'  => env('DB_PASSWORD', ''),
        'charset'   => 'utf8',
        'collation' => 'utf8_unicode_ci',
        'prefix'    => '',
            'strict'    => false,
        ],

    ],

    // other stuff

];

I'm using the sqlite database in memory which is a lot faster. You can't use it in functional or acceptance tests though.

And now a snippet of my tests/unit/TestCase.php. I set up the DB_DEFAULT variable which switches the database driver for each test. That way, I can run my unit/integration tests without having a separate .env.unit file.

<?php namespace UnitTests;

use Illuminate\Support\Facades\Artisan;

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

    /**
     * Creates the application.
     *
     * @return \Illuminate\Foundation\Application
     */
    public function createApplication()
    {
        putenv('DB_DEFAULT=sqlite_testing');

        $app = require __DIR__ . '/../../bootstrap/app.php';

        $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();
    }

}

Final note. As of this moment, running composer require "codeception/codeception:*" will get you the version 2.0.11. Running functional tests with Laravel 5 module will through a fatal error.

https://github.com/Codeception/Codeception/pull/1756

That will be fixed in 2.0.12, but for now you can install the latest dev version: composer require "codeception/codeception": "2.0.*@dev"

etbal
etbal
1 year ago (5,245 XP)

Just a note, the environment variable for database has changed,

putenv('DB_DEFAULT=sqlite_testing');

must change to

putenv('DB_CONNECTION=sqlite_testing');
mahmoudz
  1. open the config file database.php and add the following inside the 'connections' => [
'sqlite_testing' => [
    'driver'   => 'sqlite',
    'database' => ':memory:',
    'prefix'   => '',
],

this in memory sqlite will be used for your testing

  1. open the .env file and make sure it has the following:
DB_CONNECTION=mysql
  1. open phpunit.xml and add the following inside the tag:
<env name="DB_CONNECTION" value="sqlite_testing"/>

here’s where you can add all the testing related env variables

  1. in your tests were you use a database connection use the Database Migration Trait:
use DatabaseMigrations;

for more details about the DatabaseMigrations refer to the documentation https://laravel.com/docs/5.1/testing#resetting-the-database-after-each-test

travis.miller

Really late to the party on this one but I wanted to add a some what simpler solution should others arrive here like I did via search...

When looking at the laravel docs ( https://laravel.com/docs/5.2/configuration#environment-configuration ) I noticed a small paragraph that makes all the difference:

If the APP_ENV environment variable is set before bootstrapping the application, Laravel will attempt to load a file that matches the environment.

The key piece is before bootstrapping. So consider:

php artisan migrate --env=testing

This does in fact set the environment=testing however it does so AFTER the app has bootstrapped so it will read the .env not the .env.testing

Now consider:

APP_ENV=testing php artisan migrate

In this case APP_ENV is set BEFORE the app bootstraps so it will read .env.testing and not .env.

So, if you set your DB_NAME to something like pgsql_testing in your .env.testing and then run your migrations with the environment variable set via the command line it will all jive.

Hope it helps!

rolly

I am using this 'env name="DB_DATABASE" value="test_db"' in the phpunit.xml file located in the root project And it works fine for me when i run phpunit from console. If u are using phpstorm, u need to set the phpunit.xml file in the preferences/php/phpunit/Test runner/ check Default configuration file and find the file phpunit.xml in the root project.

Have fun.

Sign In or create a forum account to participate in this discussion.