Speeding up PHPunit tests and Behat in Laravel for Database refreshes

Posted: 2014-11-06 11:58:14

This article covers some good tips on this. Ideally you do not hit the database in unit tests but sometimes you do. Also in behat it hits the db all the time since it is at the Acceptance level.

Sqlite

It is a great database and works. We easily can use it on running tests. When seeding the db I have my main seeding class doing this

<?php

use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;

class DatabaseSeeder extends Seeder {

    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        Model::unguard();

        if(App::environment() != 'testing') {
            DB::statement('SET FOREIGN_KEY_CHECKS=0;');
        }

        $this->call('AppTableSeeder');
        $this->call('ParentRequestExample');
        $this->call('ProductionSeeder');
        if(App::environment() != 'testing') {
            DB::statement('SET FOREIGN_KEY_CHECKS=1;');
        }


    }

}

Since sqlite does not like this we skip it for it but not for production etc.

Second my config/testing/database.php looks like this (as noted in the article)

<?php


return [

    'default' => 'sqlite',

    'connections' => [

        'mysql' => [
            'driver'    => 'mysql',
            'host'      => $_ENV['DB_URL'],
            'database'  => $_ENV['DB_NAME'],
            'username'  => $_ENV['MYSQL_USER'],
            'password'  => $_ENV['MYSQL_PASSWORD'],

            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
        ],

        'pgsql' => [
            'driver'   => 'pgsql',
            'host'     => 'localhost',
            'database' => 'homestead',
            'username' => 'homestead',
            'password' => 'secret',
            'charset'  => 'utf8',
            'prefix'   => '',
            'schema'   => 'public',
        ],

        'setup' => array(
            'driver' => 'sqlite',
            'database' => __DIR__.'/../../database/stubdb.sqlite',
            'prefix' => '',
        ),

        'sqlite' => array(
            'driver'   => 'sqlite',
            'database' => __DIR__ . '/../../database/testing.sqlite',
            'prefix'   => '',
        ),

    ],

];

Which makes the below seeding command to setup the stub db work

php artisan migrate:refresh --seed --database="setup" --env="testing"

PHPUnit

What I ended up with is a base TestCase like this


public function setUp() { parent::setUp(); $this->faker = Faker::create(); $this->prepareForTests(); } private function prepareForTests() { if(!file_exists(base_path() . '/app/database/testing.sqlite')) { $this->refreshDb(); } } public function refreshDb() { copy(base_path() . '/app/database/stubdb.sqlite', base_path() . '/app/database/testing.sqlite'); }

And with any new migrations I run this command

php artisan migrate:refresh --seed --database="setup" --env="testing"

That file is kept in git since it is just seed data. If there are any conflicts just rm and start over. Testing.sqlite is not kept in git.

Behat

Behat is the same idea. In the main FeatureContext file I have


/** * @Given /^I reseed the database$/ */ public function iReseedTheDatabase() { try { dd(getenv('APP_ENV')); //exec("php artisan migrate:refresh --seed"); copy(__DIR__ . '/../../../../database/stubdb.sqlite', __DIR__ . '/../../../../database/testing.sqlite'); } catch(\Exception $e) { throw new \Exception(sprintf("Error seeding the database %s", $e->getMessage())); } }

So as we test the ui or api we can reload the data.

Behat / Laravel

This package https://github.com/GuilhermeGuitte/behat-laravel

This integrates behat into artisan command line helping with environment settings for behat.