Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Migrate and seed before the full test suite in Laravel with in memory database?

I'm trying to set up the test environment in my Laravel project. I'm using http://packalyst.com/packages/package/mayconbordin/l5-fixtures with json for the seeding with a sqlite in memory database and calling:

Artisan::call('migrate');
Artisan::call('db:seed');

in my setUp function but this is executed before every single test which it can grow to thousands in this project.

I tried the setUpBeforeClass but it didn't work. I think there because the createApplication method is called in every test and that reset the whole application and also wasn't loading the fixtures from the json probably for the same reason.

like image 927
Franklin Rivero Avatar asked Jul 25 '16 17:07

Franklin Rivero


People also ask

What is difference between migrate fresh and refresh in Laravel?

php artisan migrate:fresh is used when we want a fresh or new installation of our database. It deletes all the existing tables of the database and runs the migrate command. php artisan migrate:refresh is a two in one command that executes the :rollback command and the migrate command.

What is migration file explain it in brief with example in Laravel?

Laravel Migration is an essential feature in Laravel that allows you to create a table in your database. It allows you to modify and share the application's database schema. You can modify the table by adding a new column or deleting an existing column.

What does Laravel use for seeding?

Laravel includes the ability to seed your database with data using seed classes. All seed classes are stored in the database/seeders directory. By default, a DatabaseSeeder class is defined for you. From this class, you may use the call method to run other seed classes, allowing you to control the seeding order.

What are migrations and seeders in Laravel?

Migrations and seeders are powerful database utilities provided by the Laravel PHP framework to allow developers to quickly bootstrap, destroy and recreate an application’s database.

How do I create a migration schema in Laravel?

To create a migration, we use laravel’s artisan command make:migration Full command is php artisan make:migration schema_name . Using this command, laravel generates a table schema with the name that you have provided in the database/migration directory.

How to create a new migration class using artisan in Laravel?

The artisan command line tool that ships with Laravel contains a series of helper commands that can be used to manage the application and bootstrap new classes. To generate a new migration class, we can use the make:migration command as follows:

How do I seed a class in Laravel?

Laravel makes it pretty easy to perform seeding. A seeder class contains a run method by default. You can insert data by using a query builder or Eloquent model factories. Let’s run an Artisan command to generate a seeder. Then, you use the model factory to generate ten users in the run method.


2 Answers

This is how I did it in case someone else is struggling with the same, I created a base testClase class that inherits from Laravel's and did this:

/**
 * Creates the application.
 *
 * @return \Illuminate\Foundation\Application
 */
public function createApplication()
{
    return self::initialize();
}

private static $configurationApp = null;
public static function initialize(){

    if(is_null(self::$configurationApp)){
        $app = require __DIR__.'/../bootstrap/app.php';

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

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

        if (config('database.default') == 'sqlite') {
            $db = app()->make('db');
            $db->connection()->getPdo()->exec("pragma foreign_keys=1");
        }

        Artisan::call('migrate');
        Artisan::call('db:seed');

        self::$configurationApp = $app;
        return $app;
    }

    return self::$configurationApp;
}

public function tearDown()
{
    if ($this->app) {
        foreach ($this->beforeApplicationDestroyedCallbacks as $callback) {
            call_user_func($callback);
        }

    }

    $this->setUpHasRun = false;

    if (property_exists($this, 'serverVariables')) {
        $this->serverVariables = [];
    }

    if (class_exists('Mockery')) {
        Mockery::close();
    }

    $this->afterApplicationCreatedCallbacks = [];
    $this->beforeApplicationDestroyedCallbacks = [];
}

I overwrote the createApplication() and tearDown() methods. I changed the first one to use the same $app configuration and remove the part of the teardown() where it flush $this->app.

Every other of my test has to inherit from this TestClass and that's it.

Everything else didn't work. This works even with in memory database, it's 100s times faster.

if you are dealing with user session, once you log the user in you will have to log him out in tear down, otherwise the user will be logged in because the app environment is never reconstructed or you can do something like this to refresh the application every time you want:

protected static $applicationRefreshed = false;

/**
 * Refresh the application instance.
 *
 * @return void
 */
protected function forceRefreshApplication() {
    if (!is_null($this->app)) {
        $this->app->flush();
    }
    $this->app = null;
    self::$configurationApp = null;
    self::$applicationRefreshed = true;
    parent::refreshApplication();
}

And add this to the tearDown() before the $this->setUphasRun = false;:

if (self::$applicationRefreshed) {
        self::$applicationRefreshed = false;
        $this->app->flush();
        $this->app = null;
        self::$configurationApp = null;
}
like image 110
Franklin Rivero Avatar answered Oct 09 '22 19:10

Franklin Rivero


create file in your project testrunner with this content (also prepare .env.testing file with testing environment variables) :

php artisan migrate:rollback --env=testing
php artisan migrate --env=testing --seed
vendor/bin/phpunit

And give permission to execute by command chmod +x testrunner and execute it by ./testrunner. Thats all :)

like image 35
Kamil Kiełczewski Avatar answered Oct 09 '22 21:10

Kamil Kiełczewski