0
0
LaravelHow-ToBeginner · 3 min read

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

TraitPurposeWhen to Use
DatabaseTransactionsWraps each test in a transaction and rolls back after testFor fast tests that only modify data, not schema
RefreshDatabaseMigrates database before each test and rolls back changesWhen 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.