How to Use Database Transactions in Tests in Laravel
In Laravel, use the
RefreshDatabase or DatabaseTransactions trait in your test class to run each test inside a database transaction that rolls back after the test finishes. This keeps your database clean and ensures tests do not affect each other.Syntax
Laravel provides two main traits to handle database transactions in tests:
- DatabaseTransactions: Wraps each test in a transaction and rolls it back after the test.
- RefreshDatabase: Migrates the database before each test and rolls back changes, useful for tests that modify schema.
Use these traits by adding use DatabaseTransactions; or use RefreshDatabase; inside your test class.
php
<?php use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\DatabaseTransactions; class ExampleTest extends TestCase { use DatabaseTransactions; // or use RefreshDatabase; public function test_example() { // Your test code here } }
Example
This example shows a test using the DatabaseTransactions trait. It creates a user in the database, asserts the user exists, and after the test finishes, the database changes are rolled back automatically.
php
<?php use Illuminate\Foundation\Testing\DatabaseTransactions; use App\Models\User; class UserTest extends TestCase { use DatabaseTransactions; public function test_user_creation() { $user = User::factory()->create(['name' => 'Alice']); $this->assertDatabaseHas('users', ['name' => 'Alice']); } }
Output
PASS Tests\Feature\UserTest
✓ test_user_creation
Common Pitfalls
1. Using DatabaseTransactions with tests that use multiple database connections may not rollback all changes.
2. Avoid using RefreshDatabase with DatabaseTransactions together as they serve different purposes.
3. If your test triggers code that commits transactions manually, the rollback trait won't undo those changes.
php
<?php // Wrong: Using both traits together class WrongTest extends TestCase { use DatabaseTransactions, RefreshDatabase; // Avoid this } // Right: Use only one class RightTest extends TestCase { use RefreshDatabase; }
Quick Reference
| Trait | Purpose | When to Use |
|---|---|---|
| DatabaseTransactions | Wraps each test in a transaction and rolls back after test | For fast tests that only modify data, not schema |
| RefreshDatabase | Migrates database before each test and rolls back changes | When tests modify database schema or need fresh migrations |
Key Takeaways
Use
DatabaseTransactions trait to wrap tests in transactions that rollback automatically.Use
RefreshDatabase trait when your tests need fresh migrations or schema changes.Do not combine
DatabaseTransactions and RefreshDatabase traits in the same test class.Be aware that manual commits inside your code can prevent rollback from working.
Using transactions in tests keeps your database clean and tests isolated.