Laravel Testing con Pest 5 nel 2026: TIA, Mocking e Domande da Colloquio
Best practice per il testing Laravel con Pest 5, Test Impact Analysis, Mockery, facade fake e test architetturali. Unit test, feature test, strategie di mocking e domande frequenti nei colloqui per sviluppatori Laravel.

Le best practice per il testing Laravel sono cambiate radicalmente con Pest 5, la TIA engine (Test Impact Analysis) e PHPUnit 13. Laravel 13 include il supporto nativo per Pest, rendendo l'esperienza di testing piu espressiva e meno verbosa rispetto a PHPUnit puro. Questa guida copre i pattern essenziali sia per le applicazioni in produzione che per i colloqui tecnici.
Pest 5 (basato su PHPUnit 13) e il framework di testing predefinito per Laravel 13. Richiede PHP 8.4+ e introduce la TIA engine, verifica first-party per AI agent, integrazione PHPStan e sharding bilanciato nel tempo.
Configurare Pest 5 in un Progetto Laravel 13
Ogni nuova applicazione Laravel 13 viene scaffoldata automaticamente con Pest. Per i progetti esistenti, la migrazione da Pest 4 richiede pochi minuti, dato che la compatibilita con PHPUnit 13 rappresenta il cambiamento principale. La configurazione risiede in tests/Pest.php, dove vengono registrati i trait globali e i metodi helper.
use Illuminate\Foundation\Testing\RefreshDatabase;
pest()
->extend(Tests\TestCase::class)
->use(RefreshDatabase::class)
->in('Feature');Questo singolo file sostituisce il vecchio trait CreatesApplication e l'ereditarieta della classe base di test. Il trait RefreshDatabase incapsula ogni test in una transazione del database, annullando automaticamente le modifiche.
use App\Models\User;
it('registers a new user with valid data', function () {
$response = $this->postJson('/api/register', [
'name' => 'Jane Doe',
'email' => 'jane@example.com',
'password' => 'SecurePass123!',
'password_confirmation' => 'SecurePass123!',
]);
$response->assertStatus(201)
->assertJsonStructure(['user' => ['id', 'name', 'email']]);
expect(User::where('email', 'jane@example.com')->exists())->toBeTrue();
});L'API expect() di Pest si integra con le assertion di PHPUnit. La chiamata assertJsonStructure valida la struttura della risposta, mentre expect()->toBeTrue() conferma lo stato del database. Entrambi gli stili coesistono senza conflitti.
Test Impact Analysis: La Novita Principale di Pest 5
La TIA engine rende Pest 5 trasformativo per codebase di grandi dimensioni. Al primo run, Pest registra quali test toccano quali file. Ogni run successivo esegue solo i test influenzati dalle modifiche e riproduce i risultati in cache per tutto il resto.
# First run: records baseline (requires PCOV or Xdebug)
php artisan test
# Subsequent runs: only affected tests execute
php artisan testLa test suite di Laravel Cloud, con oltre 19.000 test, e scesa da circa tre minuti a cinque secondi con TIA attivato. L'engine rileva piu dei soli file PHP: individua modifiche nelle migration, nei template Blade e nei componenti JavaScript condivisi.
TIA richiede un coverage driver (PCOV o Xdebug) per registrare la baseline. Per le pipeline CI, le mappature in cache persistono tra i run, rendendo il guadagno di performance cumulativo.
Unit Test vs Feature Test in Laravel
La distinzione tra unit test e feature test in Laravel determina quali parti del framework vengono avviate. Gli unit test vengono eseguiti senza il container dell'applicazione, risultando piu veloci ma limitati alla logica pura. I feature test avviano l'applicazione completa, abilitando chiamate HTTP, query al database e risoluzione dei servizi.
use App\Services\PriceCalculator;
describe('PriceCalculator', function () {
it('applies a percentage discount correctly', function () {
$calculator = new PriceCalculator();
// 20% off a 150.00 base price
$result = $calculator->applyDiscount(150.00, 20);
expect($result)->toBe(120.00);
});
it('rejects negative discount values', function () {
$calculator = new PriceCalculator();
expect(fn () => $calculator->applyDiscount(100.00, -5))
->toThrow(InvalidArgumentException::class);
});
});Gli unit test puntano a classi isolate senza dipendenze esterne. Il blocco describe raggruppa le assertion correlate, e Pest 5 supporta blocchi describe annidati per gerarchie di test complesse.
I feature test dovrebbero costituire la maggior parte di una test suite Laravel. Rilevano bug di integrazione che gli unit test non individuano, come middleware di route errati, regole di validazione mancanti o relazioni Eloquent difettose. La regola generale e: se il codice interagisce con il database, il livello HTTP o una facade, occorre scrivere un feature test.
Strategie di Mocking con le Facade e Mockery
Il mocking nel testing Laravel isola il codice sotto test dalle dipendenze esterne. Le facade di Laravel forniscono implementazioni fake integrate per code, eventi, notifiche, mail e storage. Mockery gestisce tutto il resto.
use App\Models\Order;
use App\Models\User;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Queue;
use App\Mail\OrderConfirmation;
use App\Jobs\ProcessPayment;
it('dispatches payment job and sends confirmation email', function () {
// Fake both Mail and Queue facades
Mail::fake();
Queue::fake();
$user = User::factory()->create();
$order = Order::factory()->for($user)->create([
'total' => 99.99,
'status' => 'pending',
]);
// Act: confirm the order via HTTP
$this->actingAs($user)
->postJson("/api/orders/{$order->id}/confirm")
->assertOk();
// Assert: payment job was dispatched with correct amount
Queue::assertPushed(ProcessPayment::class, function ($job) use ($order) {
return $job->order->id === $order->id
&& $job->order->total === 99.99;
});
// Assert: confirmation email was sent to the user
Mail::assertSent(OrderConfirmation::class, function ($mail) use ($user) {
return $mail->hasTo($user->email);
});
});I facade fake intercettano le chiamate a livello di framework, impedendo l'invio effettivo di email o l'accodamento di job. Le assertion basate su closure verificano i dati esatti passati a ciascun componente.
Le classi di dominio interne non dovrebbero essere mockate. Il mocking va applicato ai confini del sistema: API di terze parti, mail, code, filesystem. Un mocking eccessivo rende i test fragili e strettamente accoppiati ai dettagli implementativi.
Per le dipendenze che non sono facade, l'iniezione avviene tramite costruttore con Mockery:
use App\Services\PaymentGateway;
use App\Services\StripeClient;
it('charges the customer through the payment gateway', function () {
// Create a mock of the Stripe client
$stripeClient = Mockery::mock(StripeClient::class);
$stripeClient->shouldReceive('charge')
->once()
->with('cus_abc123', 5000, 'usd')
->andReturn(['status' => 'succeeded', 'id' => 'ch_xyz']);
// Bind the mock in the container
$this->app->instance(StripeClient::class, $stripeClient);
$gateway = app(PaymentGateway::class);
$result = $gateway->processCharge('cus_abc123', 50.00);
expect($result['status'])->toBe('succeeded');
});Il binding del mock con $this->app->instance() sostituisce l'implementazione reale per la durata del test. Mockery verifica che charge sia stato chiamato esattamente una volta con gli argomenti attesi.
Test Architetturali con i Preset di Pest
Pest 5 include test architetturali che applicano regole strutturali all'intero codebase. Questi test vengono eseguiti sull'AST, non sul runtime, risultando estremamente veloci.
arch('controllers do not use Eloquent directly')
->expect('App\Http\Controllers')
->not->toUse('Illuminate\Database\Eloquent');
arch('services are final classes')
->expect('App\Services')
->toBeFinal();
arch('no debugging functions in production code')
->expect(['dd', 'dump', 'var_dump', 'ray'])
->not->toBeUsed();La prima regola impedisce ai controller di accedere direttamente al database, imponendo un pattern a livello di servizio. La seconda garantisce che i servizi non possano essere estesi, riducendo la complessita dell'ereditarieta. La terza intercetta istruzioni di debug dimenticate prima che raggiungano la produzione.
Sono disponibili anche preset specifici per Laravel:
arch()->preset()->laravel();
arch()->preset()->security();
arch()->preset()->php();Queste tre righe applicano decine di regole: i model devono estendere la classe base corretta, i controller non devono contenere logica di business, funzioni insicure come eval() o md5() per l'hashing sono vietate, e le convenzioni PHP standard vengono rispettate.
Pronto a superare i tuoi colloqui su Laravel?
Pratica con i nostri simulatori interattivi, flashcards e test tecnici.
Mutation Testing per Verificare la Qualita dei Test
La code coverage misura quali righe vengono eseguite durante i test. Il mutation testing va oltre: modifica il codice sorgente e verifica se i test rilevano il cambiamento. Se una mutazione sopravvive, la test suite presenta una lacuna.
# Run mutation testing on a specific class
php artisan test --mutate --class=App\\Services\\PriceCalculatorPest 5 introduce mutazioni come il cambio di > in >=, la rimozione di istruzioni return e l'inversione di condizioni booleane. Un mutation score inferiore all'80% indica generalmente che i test verificano gli output senza controllare i casi limite.
// Example: this test has high coverage but low mutation score
it('calculates shipping cost', function () {
$cost = calculateShipping(weight: 5.0, zone: 'domestic');
// Only checks that the result is numeric
expect($cost)->toBeFloat();
});
// Improved: catches mutations by asserting the exact value
it('calculates domestic shipping for 5kg package', function () {
$cost = calculateShipping(weight: 5.0, zone: 'domestic');
// Exact assertion catches operator and value mutations
expect($cost)->toBe(12.50);
});Il primo test passa anche se la logica di calcolo e completamente errata, purche restituisca un float. Il secondo test fallisce immediatamente quando una mutazione modifica la formula. Assertion specifiche producono mutation score piu elevati.
Pattern di Testing del Database e Factory
Le model factory di Laravel generano dati di test realistici senza costruzione manuale di array. Pest 5 combinato con le factory produce un setup di dati leggibile e manutenibile.
use App\Models\Article;
use App\Models\User;
it('publishes a draft article and updates the timestamp', function () {
$author = User::factory()->create(['role' => 'editor']);
$article = Article::factory()
->for($author, 'author')
->draft()
->create(['title' => 'Testing Best Practices']);
$this->actingAs($author)
->patchJson("/api/articles/{$article->id}/publish")
->assertOk()
->assertJsonPath('data.status', 'published');
$article->refresh();
expect($article->status)->toBe('published')
->and($article->published_at)->not->toBeNull()
->and($article->published_at->isToday())->toBeTrue();
});Lo state draft() della factory imposta valori predefiniti per gli articoli non pubblicati. Le assertion expect() concatenate con ->and() si leggono come linguaggio naturale e falliscono con messaggi descrittivi.
Eseguendo php artisan test --parallel i test vengono distribuiti su piu processi. Laravel crea automaticamente database di test separati per ogni processo, prevenendo conflitti tra i dati. Lo sharding bilanciato nel tempo di Pest 5 distribuisce i test in base al tempo di esecuzione effettivo invece che al numero, assicurando che ogni shard CI termini contemporaneamente.
Domande Frequenti sul Testing Laravel nei Colloqui
I colloqui tecnici per posizioni Laravel valutano frequentemente la conoscenza del testing. Ecco le domande piu ricorrenti, insieme a cio che una risposta efficace dovrebbe coprire.
Qual e la differenza tra fake(), mock() e spy() nel testing Laravel?
Facade fake() sostituisce l'intera facade con un'implementazione in memoria (Mail::fake, Queue::fake). mock() tramite Mockery imposta aspettative prima dell'esecuzione e fallisce se non vengono soddisfatte. spy() registra le interazioni e consente assertion dopo l'esecuzione, senza impostare aspettative preventive. La scelta dipende dalla necessita di verificare il comportamento (mock), registrare le interazioni (spy) o prevenire effetti collaterali (fake).
In che modo RefreshDatabase differisce da DatabaseTransactions?
RefreshDatabase esegue le migrazioni una volta e incapsula ogni test in una transazione. DatabaseTransactions presume che il database abbia gia lo schema corretto e si limita a incapsulare i test in transazioni. RefreshDatabase e piu sicuro per le pipeline CI dove il database potrebbe non esistere ancora. DatabaseTransactions e piu veloce quando lo schema e garantito essere aggiornato.
Quando i feature test sono preferibili agli unit test?
I feature test dovrebbero coprire qualsiasi codice che interagisce con il livello HTTP, il database o i servizi Laravel. Gli unit test sono riservati a funzioni pure e value object senza dipendenze dal framework. In un'applicazione Laravel tipica, i feature test superano gli unit test in un rapporto di circa 3:1 o superiore. Questo riflette la realta per cui la maggior parte del codice Laravel e intrinsecamente integrato con il framework.
Come Test Impact Analysis migliora le prestazioni CI?
TIA registra al primo run quali test toccano quali file sorgente. Nei run successivi, Pest esegue solo i test influenzati dai file modificati e riproduce i risultati in cache per i test invariati. Suite di grandi dimensioni che richiedevano minuti possono completarsi in secondi. Il compromesso: TIA richiede un coverage driver (PCOV o Xdebug) per costruire la mappa delle dipendenze, e il primo run richiede piu tempo di un run normale.
Come il mutation testing migliora la qualita dei test oltre la code coverage?
La code coverage misura i percorsi di esecuzione. Un test puo raggiungere il 100% di coverage chiamando ogni metodo senza effettuare assertion significative. Il mutation testing modifica il codice sorgente (cambia operatori, rimuove return, inverte booleani) e verifica che almeno un test fallisca. Le mutazioni sopravvissute rivelano assertion troppo permissive o del tutto assenti. php artisan test --mutate produce un mutation score percentuale insieme alla coverage standard.
Per ulteriori domande sui colloqui Laravel, la banca dati SharpSkill copre autenticazione, pattern del service container, relazioni Eloquent e architettura delle code.
Test delle Risposte HTTP e Assertion JSON
Gli helper di testing HTTP di Laravel verificano codici di stato, header, strutture JSON e destinazioni di redirect. Combinati con Pest, formano test di integrazione concisi.
use App\Models\User;
describe('API Authentication', function () {
it('rejects unauthenticated requests with 401', function () {
$this->getJson('/api/profile')
->assertUnauthorized();
});
it('returns the authenticated user profile', function () {
$user = User::factory()->create([
'name' => 'John Doe',
'email' => 'john@example.com',
]);
$this->actingAs($user)
->getJson('/api/profile')
->assertOk()
->assertJson([
'data' => [
'name' => 'John Doe',
'email' => 'john@example.com',
],
]);
});
it('validates required fields on registration', function () {
$this->postJson('/api/register', [])
->assertUnprocessable()
->assertJsonValidationErrors(['name', 'email', 'password']);
});
});Il blocco describe raggruppa i test relativi all'autenticazione. Ogni nome di test descrive il comportamento atteso, non l'implementazione. Il metodo assertJsonValidationErrors verifica che campi specifici contengano messaggi di errore di validazione.
Sources
- Pest 5 Released di Laravel News, con annuncio della TIA engine, Agent plugin ed Evals
- Pest 5 Now Available, documentazione ufficiale con requisiti e nuove funzionalita
- What We Know About Laravel 13, su PHP Attributes, AI SDK e rilascio a marzo 2026
- PHPUnit 13 Release Announcement, con dettagli su nuove assertion e deprecation
Punti Chiave sul Testing Laravel con Pest 5
- Pest 5 con Laravel 13 elimina il boilerplate attraverso un'API di configurazione fluida, catene
expect()e individuazione automatica dei test - La TIA engine riesegue solo i test interessati, riducendo l'esecuzione di suite di grandi dimensioni da minuti a secondi senza sacrificare l'accuratezza della coverage
- I feature test dovrebbero costituire il nucleo di una test suite Laravel, con gli unit test riservati alla logica di business isolata
- I facade fake (
Mail::fake(),Queue::fake()) gestiscono il mocking a livello di framework, mentre Mockery gestisce le dipendenze di terze parti iniettate tramite il container - I test architetturali applicano regole strutturali (niente Eloquent nei controller, niente funzioni di debug) senza overhead a runtime
- Il mutation testing con
--mutateindividua assertion deboli che la sola code coverage non rileva - I factory state e le assertion concatenate
expect()->and()mantengono il setup dei dati di test leggibile e le assertion specifiche - Per la preparazione ai colloqui Laravel, la comprensione di mock/fake/spy, del comportamento di
RefreshDatabase, TIA e mutation testing dimostra una maturita nel testing che va oltre la semplice coverage
Inizia a praticare!
Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.
Sapresti trovare il bug in Laravel?
Uno snippet reale, un bug nascosto, un tentativo al giorno. Senza account per provare.

Scritto da
Anthony Fillion-MailletFondatore di SharpSkill
Sviluppatore fullstack da oltre 10 anni. Guida SharpSkill e risponde di tutto ciò che vi viene pubblicato.
Aggiornato il 2 settembre 2026
Tag
Condividi
Articoli correlati

Laravel 12 nel 2026: Nuove Funzionalità, Starter Kit e Domande per Colloqui
Laravel 12 introduce Starter Kit completamente riprogettati con React 19, Vue 3, Livewire 4 e WorkOS AuthKit. Una guida completa alle nuove funzionalità, al percorso di aggiornamento e alle domande chiave per i colloqui tecnici del 2026.

Laravel Solutions: Pattern Avanzati, Debugging e Domande da Colloquio 2026
Padroneggia le soluzioni Laravel con pattern architetturali avanzati, tecniche di debugging e preparazione ai colloqui. Service class, repository pattern, debugging con Telescope e domande frequenti per sviluppatori Laravel.

Domande per colloqui Laravel e PHP: le Top 25 nel 2026
Le 25 domande piu frequenti nei colloqui Laravel e PHP. Eloquent ORM, middleware, Artisan, code, test e architettura con risposte dettagliate ed esempi di codice.