Recentemente ho avuto modo di lavorare ad una code base piuttosto grande che viene evoluta e mantenuta da un bel po’ di tempo. Quando arriva il momento di fare refactoring speri sempre di avere a disposizione una bella e scintillante suite di test su cui fare affidamento ma sappiamo tutti bene che, nel mondo vero, questo non è sempre possibile, specialmente se parliamo di codice e applicazioni non proprio recenti.
Cercando di risolvere la questione mi sono imbattuto in CgiHttpKernel, una piccola libreria che mi ha permesso di testare agevolmente gli script legacy con cui avevo a che fare.
In questo post voglio condividere brevemente quello che ho imparato dopo i primi utilizzi.
Il problema
Se ti è mai capitato di fare refactoring su un vecchio pezzo di codice dovresti conoscere bene la sensazione, soprattutto se sei abituato a lavorare con framework moderni. Ti puoi tranquillamente dimenticare i bei tool di testing a cui sei abituato, le certezze di un’applicazione MVC o magari un po’ di separazione tra logica e rappresentazione. D’improvviso ti trovi ad avere a che fare con echo, exit, header, setcookie tutti ben miscelati insieme in un’unica, compatta, palla di spaghetti code.
Devi fare refactoring di quello che hai per le mani, migliorarlo, magari introdurre qualche evoluzione, ma non puoi permetterti di introdurre regressioni. Hai bisogno di un qualche tipo di test che ti garantisca di non aver modificato il comportamento dello script in maniera involontaria, ma testare questo tipo di codice non è proprio scontato
Per nostra fortuna esiste CgiHttpKernel
La soluzione
La soluzione è tanto semplice quanto furba: CGI. Ce l’abbiamo avuto sotto il naso per tanto tempo che quasi sembra strano parlarne in un contesto del genere. CGI non è altro che un semplice modo per dialogare con un’applicazione usando le UNIX pipes. Usando quest’interfaccia è molto semplice fingere di essere un web server ed eseguire più o meno qualsiasi tipo di applicazione, anche il più contorto, intricato e oscuro degli script PHP
Nel mondo PHP avevamo già tutti i pezzi del puzzle: php-cgi e HttpKernelInterface, quello che mancava era solo un po’ di colla per metterli insieme. Fortunatamente la nostra community è piena di gente sveglia e Igor Wiedler c’ha messo la pezza
Usando CgiHttpKernel puoi interagire con qualsiasi applicazione PHP, dal singolo script fino alla complessa applicazione zend framework, inviandole richieste SymfonyComponentHttpFoundationRequest e risposte SymfonyComponentHttpFoundationResponse.
A questo punto puoi usare qualsiasi libreria che si integra con HttpKernelInterface.
La tua applicazione legacy ha appena fatto un salto in avanti nello sviluppo PHP moderno.
Vediamo un esempio
In realtà non è necessario, l’utilizzo della libreria è molto semplice e assolutamente ben documentato, puoi trovare tutto quello che ti serve direttamente nel readme del progetto, senza bisogno che io duplichi qui snippet di codice.
Voglio invece condividere una note riguardo un problema che ho avuto e che mi ha portato via un po’ di tempo. Apparentemente usando path relativi per lo script da testare, php-cgi non riesce a risolverli correttamente e restituisce un 404. Non sono sicuro se la cosa sia un bug di php-cgi o dell’implementazione del kernel, ma il problema è facilmente risolvibile convertendo i path relativi in assoluti con realpath.
In pratica:
$kernel = new CgiHttpKernel(__DIR__ . '/../../../your/src/root/dir')
diventa:
$kernel = new CgiHttpKernel(realpath(__DIR__ . '/../../../your/src/root/dir'));
e tutto funziona perfettamente.