Laravel create database when testing

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Mastering Database Setup in Laravel Testing: Why Manual Commands Fail and How to Succeed

As a senior developer working with the Laravel ecosystem, we frequently encounter challenges when setting up test environments. One of the most common hurdles is managing the database state for unit or feature tests. When attempting to manually execute raw SQL commands like CREATE DATABASE within your setUp() method, developers often run into confusing errors like Unknown database or database exists.

This post dives deep into why your current setup fails, presents the robust, idiomatic Laravel solution, and provides a practical guide on how to correctly manage your test databases.

The Pitfall of Manual Database Management in Tests

The scenario you described—where DROP DATABASE works but CREATE DATABASE fails within your test setup—points directly to a conflict between manual SQL execution and Laravel's underlying testing framework, specifically how it manages database connections and transactions.

When you use DB::statement('create database coretest;'), you are executing a raw command against the configured connection. However, in a typical Laravel test environment, especially when using tools like PHPUnit, the framework relies heavily on migrations to define and manage the schema. Manually creating or dropping databases outside of this defined migration lifecycle often confuses the PDO layer or the underlying database server's state management, leading to unpredictable errors.

The core issue is that unit tests should focus on testing application logic, not managing the physical infrastructure setup—that job belongs to migrations.

The Laravel Best Practice: Embrace Migrations

The definitive, most reliable way to set up your test database in Laravel is by leveraging the built-in migration system. This approach ensures that your test environment perfectly mirrors how your production application builds and updates its schema.

Laravel provides powerful testing traits that automate this process seamlessly. By using the RefreshDatabase trait, you instruct Laravel to run all migrations before each test and roll them back afterward. This guarantees a clean, isolated, and reproducible state for every single test execution.

Implementing the Refresh Database Strategy

Instead of relying on raw SQL in setUp(), configure your test class to use traits that handle database seeding automatically.

Here is how you should restructure your TestCase:

<?php

namespace Tests;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

class TestCase extends BaseTestCase
{
    // Use the RefreshDatabase trait to handle setup and teardown automatically.
    use RefreshDatabase;

    /**
     * Default preparation for each test
     */
    // No need for manual DB::statement calls here!
    public function setUp(): void
    {
        parent::setUp();
        // All migrations will be run by the trait before this method is fully executed.
    }

    // The tearDown() method is no longer needed for database dropping, 
    // as RefreshDatabase handles the rollback automatically.
}

When you use RefreshDatabase, Laravel automatically manages the creation and rollback of the necessary tables defined in your migration files before and after each test. This solves the error entirely by letting Laravel manage the database lifecycle correctly. For further insights into robust infrastructure management within the framework, exploring concepts like dependency injection and service container is key to building scalable applications, as discussed on the Laravel Company documentation.

Conclusion: Focus on Logic, Not Infrastructure

Trying to force manual database creation within test setup methods is an anti-pattern in modern Laravel development. It introduces fragility, conflicts with the framework's intended workflow, and leads to debugging nightmares like the ones you encountered.

The solution is simple: delegate infrastructure management to your migrations. By adopting traits like RefreshDatabase, you ensure that your tests are fast, isolated, and reflect genuine application behavior. Focus your testing efforts on verifying business logic and controller interactions, letting Laravel handle the heavy lifting of database preparation behind the scenes.