How to Migrate and seed before the full test suite in Laravel with in memory database?
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;
}
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 :)