steros
steros

Reputation: 1924

how to run unittests in laravel 5.5 using a sqlite in memory database

I setup a test database:

phpunit.xml:

<phpunit>
    <!... other stuff ...>
    <php>
        <env name="APP_ENV" value="testing"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
        <env name="DB_CONNECTION" value="sqlite_testing"/>
    </php>
</phpunit>

database.php:

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

DatabaseSeeder.php

<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $this->call([
            MyTableSeeder::class
        ]);
    }
}

MyTableSeeder.php:

<?php

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use App\My\Model;

class MyTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        DB::table('model')->insert([
            'id' => 1,
            'created_at' => \Carbon\Carbon::now(),
            'updated_at' => \Carbon\Carbon::now()
        ]);

        /**
         * create random data
         */
        factory(Model::class, 50)->create();
    }
}

ModelFactory.php:

<?php

use Faker\Generator as Faker;

$factory->define(\App\My\Model::class, function (Faker $faker) {
    return [
        'id' => $faker->unique()->randomNumber(),
        'created_at' => $faker->dateTime('now'),
        'updated_at' => $faker->dateTime('now')
    ];
});

MyTest.php:

<?php

namespace Tests\Unit;

use App\My\Model;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;

class MyTest extends TestCase
{
    use RefreshDatabase;

    public function testGettingModel() {
        var_dump(Model::all()); // <-- returns a collection without any items

        $model = Model::where('id', 1)->first();

        $this->assertEquals('1', $model->id); // <-- trying to get property of non-object
    }
}

So at the test run it seems the database is migrated by the trait but not seeded and thus nothing is returned. The documentation does not state however (or I couldn't find it) how to seed the database upon testing. It states how to manually seed by running "php artisan db:seed" but that's not working in a test obviously as the database doesn't exist anymore after the test. And I can't run it manually as the database doesn't exist before the test. Also that would make testing impractical.

Some examples state running the seeding before testing in the setup method of the test like so:

public function setUp() {
    Artisan::call('db:seed');
}

But including this statement leads to the error:

RuntimeException : A facade root has not been set. (in /vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:218)

Alternatively running it like so:

public function setUp()
{
    $this->artisan('db:seed');
}

Leads to:

Error : Call to a member function call() on null (in /vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php:18)

How do I actually do this? Is there any fully working example anywhere? So far I couldn't find any :(

Upvotes: 3

Views: 2454

Answers (1)

steros
steros

Reputation: 1924

You have to call $this->seed(); in the setUp method. But you need to ensure to call the parents setUp method before or it will fail.

<?php

namespace Tests\Unit;

use App\My\Model;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;

class MyTest extends TestCase
{
    use RefreshDatabase;

    public function setUp()
    {
        parent::setUp();
        $this->seed();
    }

    public function testGettingModel() {
        $model = Model::where('id', 1)->first();
        $this->assertEquals('1', $model->id); // will assert to true if the id actually exists
    }
}

Upvotes: 1

Related Questions