Vai al contenuto principale

Introduzione

Laravel include di serie i meccanismi per testare in modo sicuro e veloce le funzionalità che usano il database. Combinando i trait per il reset del database, le model factory, i seeder e le asserzioni dedicate crei test difficili da rompere. Il punto di partenza è RefreshDatabase. Nella maggior parte dei casi mantiene l’indipendenza dei test più rapidamente di un reset completo.

Reset del database dopo ogni test

Per evitare che i dati di un test influenzino il successivo, usa i trait di reset del database.
<?php

use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('esempio base', function () {
    $response = $this->get('/');

    $response->assertOk();
});
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class ExampleTest extends TestCase
{
    use RefreshDatabase;

    public function test_basic_example(): void
    {
        $response = $this->get('/');

        $response->assertOk();
    }
}
RefreshDatabase verifica se lo schema è aggiornato. Se lo è, esegue il test in una transazione; se no, esegue prima le migration. Se preferisci un reset completo ogni volta anziché la transazione, usa questi trait.
TraitComportamentoQuando usarlo
RefreshDatabaseTransazione se lo schema è aggiornato; migration solo quando servePrima scelta di default
DatabaseMigrationsEsegue le migration a ogni testSe vuoi passare per l’intero ciclo di migration ogni volta
DatabaseTruncationFa TRUNCATE delle tabelleSe le transazioni non sono adatte al tuo ambiente e vuoi svuotare tutto

Model factory

Per preparare dati prima di un test, con le model factory generi modelli Eloquent in modo conciso. Per dettagli su definizioni, state e relazioni consulta Factory Eloquent.
<?php

use App\Models\User;

test('è possibile creare modelli', function () {
    $user = User::factory()->create();

    expect($user->exists)->toBeTrue();
});
<?php

namespace Tests\Feature;

use App\Models\User;
use Tests\TestCase;

class UserFactoryTest extends TestCase
{
    public function test_models_can_be_instantiated(): void
    {
        $user = User::factory()->create();

        $this->assertTrue($user->exists);
    }
}

Esecuzione dei seeder

Per inserire dati durante il test usa seed(). Senza argomenti esegue DatabaseSeeder; con un argomento esegue un seeder specifico (o un array).
<?php

use Database\Seeders\OrderStatusSeeder;
use Database\Seeders\TransactionStatusSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('è possibile creare ordini', function () {
    $this->seed();

    $this->seed(OrderStatusSeeder::class);

    $this->seed([
        OrderStatusSeeder::class,
        TransactionStatusSeeder::class,
    ]);

    // ...
});
<?php

namespace Tests\Feature;

use Database\Seeders\OrderStatusSeeder;
use Database\Seeders\TransactionStatusSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class OrderTest extends TestCase
{
    use RefreshDatabase;

    public function test_orders_can_be_created(): void
    {
        $this->seed();

        $this->seed(OrderStatusSeeder::class);

        $this->seed([
            OrderStatusSeeder::class,
            TransactionStatusSeeder::class,
        ]);

        // ...
    }
}
Per seedare automaticamente in tutti i test che usano RefreshDatabase, aggiungi l’attribute #[Seed] alla classe base di test.
<?php

namespace Tests;

use Illuminate\Foundation\Testing\Attributes\Seed;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

#[Seed]
abstract class TestCase extends BaseTestCase
{
}
Per eseguire automaticamente solo alcuni seeder usa #[Seeder(...)].
<?php

namespace Tests\Feature;

use Database\Seeders\OrderStatusSeeder;
use Illuminate\Foundation\Testing\Attributes\Seeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

#[Seeder(OrderStatusSeeder::class)]
class OrderStatusTest extends TestCase
{
    use RefreshDatabase;
}

Asserzioni disponibili

Laravel offre asserzioni dedicate al database utilizzabili sia in Pest sia in PHPUnit.

assertDatabaseCount

Verifica che il numero di record nella tabella corrisponda al valore atteso.
$this->assertDatabaseCount('users', 5);
$this->assertDatabaseCount('users', 5);

assertDatabaseEmpty

Verifica che la tabella sia vuota.
$this->assertDatabaseEmpty('users');
$this->assertDatabaseEmpty('users');

assertDatabaseHas

Verifica che esistano record che corrispondono alle condizioni.
$this->assertDatabaseHas('users', [
    'email' => '[email protected]',
]);
$this->assertDatabaseHas('users', [
    'email' => '[email protected]',
]);

assertDatabaseMissing

Verifica che non esistano record che corrispondono alle condizioni.
$this->assertDatabaseMissing('users', [
    'email' => '[email protected]',
]);
$this->assertDatabaseMissing('users', [
    'email' => '[email protected]',
]);

assertSoftDeleted

Verifica che il modello Eloquent sia soft deleted.
$this->assertSoftDeleted($user);
$this->assertSoftDeleted($user);

assertNotSoftDeleted

Verifica che il modello Eloquent non sia soft deleted.
$this->assertNotSoftDeleted($user);
$this->assertNotSoftDeleted($user);

assertModelExists

Verifica che il modello (o la collection di modelli) indicato esista nel DB.
<?php

use App\Models\User;

$user = User::factory()->create();

$this->assertModelExists($user);
<?php

use App\Models\User;

$user = User::factory()->create();

$this->assertModelExists($user);

assertModelMissing

Verifica che il modello (o la collection di modelli) non esista nel DB.
<?php

use App\Models\User;

$user = User::factory()->create();
$user->delete();

$this->assertModelMissing($user);
<?php

use App\Models\User;

$user = User::factory()->create();
$user->delete();

$this->assertModelMissing($user);

expectsDatabaseQueryCount

All’inizio del test indica il numero totale di query attese. Se il numero effettivo non corrisponde il test fallisce.
$this->expectsDatabaseQueryCount(5);

// Test...
$this->expectsDatabaseQueryCount(5);

// Test...
Ultima modifica il 13 luglio 2026