Testing

Aprèn a escriure tests a Laravel: PHPUnit, Pest, tests unitaris, funcionals, de base de dades, mocking i tests de navegador amb Dusk.

El testing no és un luxe ni una tasca que es fa "quan queda temps": és una part fonamental del desenvolupament de programari professional. Un projecte sense tests és un projecte on cada canvi pot trencar funcionalitats existents sense que ningú se n'adoni fins que un usuari real es trobi amb l'error. Laravel va ser dissenyat des del primer dia amb el testing en ment, i proporciona una infraestructura completa que fa que escriure tests sigui tan natural com escriure la pròpia aplicació.

Laravel inclou suport natiu per a PHPUnit, el framework de testing més establert del món PHP, i també per a Pest, un framework modern que ofereix una sintaxi més expressiva i concisa. No cal triar un o l'altre al principi: tots dos funcionen perfectament amb Laravel i pots fins i tot barrejar-los al mateix projecte. Pest, de fet, es construeix sobre PHPUnit, cosa que significa que qualsevol cosa que funcioni amb PHPUnit funciona automàticament amb Pest.

La filosofia de testing de Laravel es basa en un principi clar: els tests han de ser fàcils d'escriure i de llegir. Si escriure un test requereix configurar manualment connexions de base de dades, crear esquemes de taules, gestionar transaccions i netejar les dades després de cada test, ningú escriurà tests. Per això Laravel automatitza tot aquest procés: el trait RefreshDatabase gestiona la base de dades, les factories generen dades de prova realistes, els fakes substitueixen serveis externs per versions simulades, i els mètodes d'assertion expressen les expectatives de manera llegible.

Els tests a Laravel s'organitzen en dues categories principals segons el seu abast. Els tests unitaris proven unitats aïllades de codi: una funció que calcula un preu, un mètode que valida un format, un accessor d'un model. Són ràpids perquè no necessiten base de dades ni el framework complet. Els tests funcionals (feature tests) proven fluxos complets de l'aplicació: que un usuari pugui registrar-se, que una API retorni les dades correctes, que un formulari validi els camps obligatoris. Són més lents perquè simulen peticions HTTP reals i interactuen amb la base de dades, però donen molta més confiança que l'aplicació funciona correctament.

A més d'aquestes dues categories, Laravel ofereix eines especialitzades per a necessitats específiques. El sistema de mocking permet substituir serveis reals (correu, cues, notificacions, sistema de fitxers) per versions falses que registren les interaccions sense executar-les realment. Això permet verificar que l'aplicació envia un correu de benvinguda sense enviar cap correu real. El sistema de testing de base de dades proporciona factories, traits de refresh i assertions específiques per verificar l'estat de la base de dades. I Laravel Dusk permet fer tests de navegador complets que interactuen amb l'aplicació com ho faria un usuari real: omplint formularis, fent clic a botons i verificant que el JavaScript funciona correctament.

La clau per escriure bons tests és trobar l'equilibri adequat. Massa tests unitaris i poc tests funcionals donen una falsa sensació de seguretat: cada peça funciona aïlladament, però potser no funcionen juntes. Massa tests funcionals i poc tests unitaris fan que la suite sigui lenta i difícil de mantenir. L'enfocament recomanat és tenir una base sòlida de tests funcionals que cobreixin els fluxos principals de l'aplicació (registre, login, CRUD, pagaments) complementada amb tests unitaris per a la lògica de negoci complexa (càlculs, validacions, transformacions de dades).

Un altre aspecte fonamental és la velocitat de la suite de tests. Si executar tots els tests triga 30 minuts, ningú els executarà abans de cada commit. Laravel ofereix diverses estratègies per mantenir els tests ràpids: SQLite en memòria per a la base de dades, execució en paral·lel amb --parallel, fakes que eviten operacions costoses (enviar correus, pujar fitxers) i una arquitectura que permet executar subconjunts de tests amb --filter.