f in x
PHPUnit vs Pest per Laravel — Due Stili di Test per Codice che Non Si Rompe in Produzione
> cd .. / HUB_EDITORIALE > Visualizza in Inglese
Sviluppo di siti web

PHPUnit vs Pest per Laravel — Due Stili di Test per Codice che Non Si Rompe in Produzione

[2026-07-01] Author: Ing. Calogero Bono
Zenithby Meteora Web Il sistema operativo della tua attività. Social, clienti, prenotazioni e fatture in un'unica piattaforma. Palestre, barber, professionisti. Scopri Zenith Demo gratis · senza carta

Il problema è sempre lo stesso: il codice che hai appena scritto funziona in locale, ma in produzione si rompe perché non hai testato un caso limite. E quando il cliente chiama perché il checkout sparisce, ti ricordi che il tempo speso a scrivere test non è mai tempo perso.

Noi, di Meteora Web, lo vediamo ogni giorno. Abbiamo ereditato progetto con zero test e abbiamo passato notti a debuggare. Da lì abbiamo imparato: i test non sono un optional, sono la differenza tra un rilascio sicuro e un incidente. In questo articolo confrontiamo PHPUnit e Pest, due framework di testing per PHP e Laravel, con esempi reali tratti dalla nostra esperienza.

PHPUnit e Pest: Quali Sono le Differenze Principali?

PHPUnit è il framework storico, nato nel 2004. Pest è il nuovo arrivato (2019) che usa PHPUnit sotto il cofano ma cambia radicalmente la sintassi e l'esperienza di scrittura. Entrambi fanno la stessa cosa: eseguono asserzioni sulle tue classi. Ma il modo in cui li scrivi è diverso.

PHPUnit segue un approccio a classi: ogni test è un metodo dentro una classe che estende PHPUnit\Framework\TestCase. Pest usa funzioni globali e una sintassi fluida, ispirata a Jest (JavaScript). Pest è un wrapper di PHPUnit: puoi usare tutti i metodi di PHPUnit da Pest, ma scrivendo meno boilerplate.

Ecco un confronto visivo. Lo stesso test di una somma:

// PHPUnit
use PHPUnit\Framework\TestCase;

class MathTest extends TestCase
{
    public function test_addition()
    {
        $result = 1 + 1;
        $this->assertEquals(2, $result);
    }
}

// Pest
test('addition')
    ->with(1, 1)
    ->assertTrue(2 === 1 + 1);

Nota subito: con Pest non devi creare una classe, non devi estendere nulla. Scrivi una funzione test() e incateni asserzioni. Per molti sviluppatori è più leggibile e veloce da scrivere.

Sponsored Protocol

Come Scrivere Test con PHPUnit in Laravel?

Laravel integra PHPUnit di default. I test si trovano in tests/Unit e tests/Feature. Ecco un esempio reale: testare che una rotta API restituisca un JSON con lo stato corretto.

// tests/Feature/UserApiTest.php
namespace Tests\Feature;

use Tests\TestCase;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;

class UserApiTest extends TestCase
{
    use RefreshDatabase;

    public function test_can_fetch_users()
    {
        User::factory()->count(3)->create();

        $response = $this->getJson('/api/users');

        $response->assertStatus(200)
                 ->assertJsonCount(3)
                 ->assertJsonStructure([
                     '*' => ['id', 'name', 'email']
                 ]);
    }
}

Qui usiamo RefreshDatabase per avere un database pulito a ogni test. assertJsonCount e assertJsonStructure sono metodi di Laravel che rendono i test espressivi.

Cosa fare subito: apri il tuo progetto Laravel, vai in tests/Feature e crea un test per una delle tue route. Esegui php artisan test per vederlo passare.

Sponsored Protocol

Come Scrivere Test con Pest in Laravel?

Pest si installa con Composer e diventa il runner di default se lo preferisci. Lo stesso test di prima in Pest diventa:

// tests/Feature/UserApiTest.php
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('can fetch users via API', function () {
    User::factory()->count(3)->create();

    $response = $this->getJson('/api/users');

    $response->assertStatus(200)
             ->assertJsonCount(3)
             ->assertJsonStructure([
                 '*' => ['id', 'name', 'email']
             ]);
});

La differenza principale è la funzione uses() per applicare i trait globalmente, e l'assenza di classe. Nota anche che $this esiste comunque grazie al binding automatico di Pest.

Pest offre anche funzioni di alto livello come beforeEach() e afterEach() per preparare il contesto, e gruppi di test con describe():

describe('User API', function () {
    beforeEach(function () {
        $this->user = User::factory()->create();
    });

    test('can list users', function () {
        $response = $this->getJson('/api/users');
        $response->assertOk();
    });

    test('can create a user', function () {
        $response = $this->postJson('/api/users', [
            'name' => 'Marco',
            'email' => 'marco@example.com',
            'password' => 'secret'
        ]);
        $response->assertCreated();
    });
});

Cosa fare subito: installa Pest con composer require pestphp/pest --dev, poi esegui php artisan pest:init. Converti un tuo test esistente in Pest per sentire la differenza.

Sponsored Protocol

PHPUnit o Pest: Quale Scegliere per il Tuo Progetto?

La scelta dipende dal team e dal contesto. Noi di Meteora Web usiamo entrambi. Su progetti Laravel nuovi preferiamo Pest per la velocità di scrittura e la leggibilità. Su codebase legacy con decine di test in PHPUnit, non lo migriamo: il tempo speso a riscrivere non vale il beneficio.

Ecco una checklist per decidere:

  • Scegli PHPUnit se: hai un team abituato, molti test esistenti, o hai bisogno di compatibilità con tool CI che non riconoscono Pest (raro).
  • Scegli Pest se: inizi un nuovo progetto, vuoi test più leggibili, o hai sviluppatori che arrivano da Jest/Mocha.
  • Usa entrambi se: vuoi una transizione graduale. Pest può eseguire test PHPUnit senza problemi.

Ricorda: il framework conta meno della cultura del testing. Abbiamo visto aziende con PHPUnit perfetto e aziende con Pest disordinato. La differenza la fa la disciplina: testare prima di rilasciare, coprire i casi critici, mantenere i test verdi.

Un Esempio Reale di Test con Mocking e Database

Prendiamo un caso concreto: un servizio che calcola lo sconto su un ordine. Useremo mock per isolare le dipendenze.

Sponsored Protocol

// App\Services\DiscountService
class DiscountService
{
    public function apply(Order $order, Coupon $coupon): float
    {
        if (! $coupon->isValid()) {
            return $order->total;
        }
        return $order->total * (1 - $coupon->percentage);
    }
}

// Test con PHPUnit
class DiscountServiceTest extends TestCase
{
    public function test_applies_discount_when_coupon_valid()
    {
        $coupon = $this->createMock(Coupon::class);
        $coupon->method('isValid')->willReturn(true);
        $coupon->percentage = 0.2;

        $order = new Order(['total' => 100]);

        $service = new DiscountService();
        $result = $service->apply($order, $coupon);

        $this->assertEquals(80.0, $result);
    }
}

// Test con Pest
test('applies discount when coupon valid', function () {
    $coupon = Mockery::mock(Coupon::class);
    $coupon->shouldReceive('isValid')->andReturn(true);
    $coupon->percentage = 0.2;

    $order = new Order(['total' => 100]);
    $service = new DiscountService();

    expect($service->apply($order, $coupon))->toBe(80.0);
});

Nota: in Pest usiamo lo stesso identico PHPUnit o possiamo usare Mockery (che ha una sintassi più fluida). Non c'è una risposta giusta; l'importante è testare.

Come Integrare PHPUnit e Pest nel Workflow CI

Entrambi si integrano con GitHub Actions, GitLab CI, o qualsiasi tool. Il comando è sempre php artisan test (che usa PHPUnit di default) o ./vendor/bin/pest se hai Pest come runner. Noi consigliamo di eseguire i test su ogni pull request e di bloccare il merge se falliscono.

Sponsored Protocol

# .github/workflows/tests.yml
name: Tests
on: [push, pull_request]
jobs:
  phpunit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: shivammathur/setup-php@v2
        with:
          php-version: '8.3'
          tools: composer
      - run: composer install --no-progress
      - run: php artisan test

Cosa fare subito: aggiungi un workflow di test al tuo repository. Se non lo hai, parte da questo esempio.

Cosa Fare Adesso

  1. Scrivi un test per una funzione che usi oggi. Non serve un progetto intero: parti da una classe semplice (es. un helper per formattare date).
  2. Installa Pest su un progetto Laravel esistente e converti un test per capire se ti piace. Non serve migrare tutto.
  3. Aggiungi il workflow CI per eseguire i test automaticamente. È il modo più veloce per evitare regressioni.
  4. Leggi la documentazione ufficiale di PHPUnit e Pest per approfondire mocking e test di feature.

Noi, di Meteora Web, abbiamo visto progetti salvati da una suite di test solida. Se hai bisogno di una mano a impostare i test nel tuo progetto Laravel, parti dal nostro pillar sul testing.

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Ingegnere informatico, fondatore di Meteora Web e Zenith OS. System administrator e progettista di piattaforme, app e CMS proprietari, con esperienza in sviluppo full-stack, marketing digitale ed ecosistema Google.
[ Read Full Dossier ]

> METEORA_WEB // WEB AGENCY

Costruiamo la presenza digitale che la tua azienda merita.

Siti web, social, pubblicità online, e-commerce e hosting performante: ingegnerizzati con metodo da ingegneri informatici a Sciacca, per tutta Italia.

> MW_JOURNAL

> READ_ALL()