Reputation: 1924
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
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