Laravel PhpUnit No such table
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
Laravel Testing Nightmare: Solving the "No Such Table" Error with SQLite Migrations
As a senior developer, I’ve seen countless developers grapple with database setup issues during testing. The scenario you are facing—where your application runs fine on MySQL but throws a No such table error when running tests against an in-memory SQLite database—is extremely common and frustrating. It signals a mismatch between the environment state you expect and the actual state Laravel is creating for the test run.
This post will diagnose why this happens and provide the robust, idiomatic Laravel solution to ensure your tests interact with a correctly migrated database, regardless of whether you are using MySQL or SQLite. We'll dive into your provided code snippets and show you how to set up proper database isolation.
Diagnosing the Root Cause: Migrations vs. Test Setup
The error General error: 1 no such table: groupe_user clearly indicates that when your test code attempts to query the group_user table, that table simply does not exist in the SQLite database instance being used for testing.
This usually happens because:
- Migrations are Skipped: The mechanism responsible for running your migration files (
php artisan migrate) is either not executed correctly within the test lifecycle, or it's attempting to run against a context where those migrations haven't been applied yet. - Environment Mismatch: When testing with SQLite in memory, Laravel needs explicit instructions on how to handle schema creation. If you rely solely on manual Artisan calls inside
setUp(), you might miss necessary hooks that ensure database integrity for every test method.
Your custom TestCase correctly attempts to call Artisan::call('migrate') and Artisan::call('db:seed'). However, relying on manually calling these commands within the base test class can be brittle, especially when dealing with different database drivers like SQLite that operate differently than a persistent MySQL setup.
The Laravel Solution: Leveraging Database Refresh Traits
The most effective way to handle database setup and teardown in Laravel testing is to utilize the built-in traits provided by the framework. Instead of manually calling Artisan commands, we instruct Laravel's testing harness to manage the database state automatically for you.
For scenarios where you are using migrations (which define your schema), the RefreshDatabase trait is the gold standard. This trait ensures that before every test runs, Laravel resets the database (either dropping and recreating tables or rolling back migrations) and then re-runs all migrations.
Implementing RefreshDatabase in Your Test Case
You should modify your AuthTest.php to use this trait instead of custom migration calls within prepareForTests(). This delegates the complex task of ensuring schema integrity to Laravel, which is designed to handle these scenarios reliably, echoing the principles found in modern framework design like that promoted by laravelcompany.com.
Here is how you should refactor your test case:
<?php
use Illuminate\Foundation\Testing\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase; // Import the trait
use App\User;
// Apply the RefreshDatabase trait to ensure migrations are run before each test
class AuthTest extends TestCase
{
use RefreshDatabase; // <-- Use the trait
// You can remove or simplify your custom setUp/tearDown methods
// as the trait handles the database setup automatically.
public function testAuthLogin()
{
// Because of RefreshDatabase, the tables (groupes, group_user)
// defined in your migrations will be created before this test runs.
$user = factory(App\User::class)->create();
// Test du login
$this->visit('/login')
->see('Se Connecter')
->type('lorem@gmail.com', 'email')
->type('lorem85', 'password')
->press('Se connecter');
}
}
Why This Works for SQLite
When you use RefreshDatabase, Laravel intelligently manages the database connection. If your configuration points to an in-memory SQLite driver for testing, this trait ensures that the migration files (CreateGroupesTable) are executed against that temporary database instance before your test method attempts to query any table. This guarantees that by the time testAuthLogin executes, the groupes and group_user tables will have been successfully created, eliminating the "no such table" error.
Conclusion
Dealing with database state in testing is a critical part of building resilient applications. Avoid manually calling Artisan commands within your test setup whenever possible; instead, rely on framework-provided traits like RefreshDatabase. This approach keeps your tests clean, isolated, and perfectly synchronized with your application's migration structure. By adopting these best practices, you ensure that whether you are testing against MySQL or SQLite, your tests will always execute against a correctly structured environment, making your development workflow significantly smoother.