È la prima volta che mi capita di recensire questa piccola casa editrice americana, la Pragmatic Bookshelf, specializzata in maneggevoli libretti sugli aspetti spesso meno conosciuti e considerati (a torto) della programmazione in generale. Questi aspetti sono riconducibili a 3 grandi filoni: la programmazione cosiddetta “agile”, lo “unit testing” e l’automazione con il controllo di versione. A catalogo presenta una 40ina di titoli, la gran parte di piccole dimensioni come numero pagine (ma non come formato), in genere sulle 200/400 pagine. Il sito è questo www.pragmaticprogrammer.com
La loro caratteristica è di essere molto calati nella realtà lavorativa degli sviluppatori (non per nulla si chiama “Pragmatic”), e di fornire soluzioni pratiche, comprensibili ed immediate per problemi ricorrenti ma non strettamente legati alle tecniche di programmazione. Non viene infatti insegnato a programmare in questo o quel linguaggio (anche se a catalogo è presente un titolo dedicato a Ruby, un linguaggio di programmazione), ma si suppone che il lettore sia già un programmatore con una certa esperienza (e che conosca bene un certo linguaggio) e curioso o bisognoso di approfondire argomenti che non è facile trovare in altri libri.
Uno di questi è proprio il “Test Driven Development” (TDD), ovvero la disciplina di scrivere i test prima del codice stesso, e questo al fine, come dice l’autore, per vivere meglio e più sicuri del proprio lavoro.
In sostanza questi test sono pezzi di codice che testano altri pezzi di codice per verificare che questi ultimi svolgano correttamente il loro lavoro e forniscano il risultato atteso.
Chi già conosce questi argomenti, conoscerà senz’altro Kent Beck: il Test Driven e l’extreme programming sono partiti da lui (insieme a Martin Fowler). I loro libri sono diventati una sorta di Bibbia e migliaia di programmatori si sono formati sulle loro idee. Anche Andrew Hunt, l’autore di questo libro, nel tempo si è ritagliato una discreta reputazione, e nei suoi libri (tutti editi da Pragmatic) si ritrovano spesso le idee dei precursori Beck e Fowler.
In cosa consiste quindi il Test Driven? Affermare semplicemente che consiste nello scrivere i test prima del codice effettivo dell’applicazione è un po’ riduttivo e sicuramente limitante. Il Test Driven è una mentalità, uno schema mentale che il programmatore dovrebbe seguire per superare quella soglia che divide lo sviluppatore “smanettone”, che scrive grandi quantità di codice in poco tempo, ma spesso con bug, dallo sviluppatore “intelligente”, che si chiede prima cosa fa, o dovrebbe fare, il proprio codice, per poterlo testare man mano che lo sviluppa. In questo modo si arriva ad un punto in cui tutto il proprio software, anche prima di essere terminato, è completamente testato e verificato. La fase di debug, che in genere porta via un sacco di tempo, si riduce enormemente, i bug sono ridotti al minimo sindacale, e perciò si “vive meglio”, senza l’ansia tipica di quando si fornisce il software al cliente finale.
Per fare un esempio concreto: anche io fino ad un anno fa circa ero abituato al solito modo di sviluppare: si raccolgono i requisiti che il software dovrebbe soddisfare (spesso riassunti solo nella propria mente), e si inizia subito a scrivere codice effettivo. Magari man mano che si procede si prova (ovviamente deve almeno compilare), ma si rimanda il testing effettivo alla fine, poco prima di rilasciare il proprio lavoro. Se poi ci sono problemi o bug ci si ritrova a dover metter mano al proprio codice scritto mesi prima, quando ormai si fa fatica a capire cosa doveva fare e perché era stato scritto così. Una parte del testing effettivo è poi demandata addirittura all’utente finale, che provando per bene l’applicazione, riscontra problemi o malfunzionamenti di vario tipo. Questo, come si può capire, non agevola, e mette oltremodo in cattiva luce il proprio lavoro di sviluppatore.
Lo unit testing, se ben fatto, dovrebbe evitare tutto questo, e solo guardando i testo si dovrebbe capire cosa esattamente fa il software. Estremizzando, ma nemmeno poi molto, si potrebbe dire che i test potrebbero sostituire la documentazione del proprio codice.
Molti di quelli che hanno iniziato con il Test Driven (come me), hanno letto il libretto di Kent Beck, dove in poco più di 200 pagine vengono elargiti un sacco di consigli su come precedere, tra l’altro con un linguaggio molto ironico anche se con un inglese non semplicissimo.
Questo libro di Andrew Hunt segue la stessa strada, ma presenta il grande vantaggio di utilizzare la piattaforma di testing preferita da chi sviluppa in .NET, ovvero NUnit, e soprattutto utilizzando C# come linguaggio (nel libro di Beck si utilizza SmallTalk e Phyton, non molto intuitivi per chi non li conosce già).
Inoltre l’inglese di questo autore è molto più comprensibile, il che farà molto piacere al lettore non madrelingua anglosassone.
Idealmente questo testo costituisce il secondo volume di una trilogia: il primo testo (“Pragmatic Version Control”) riguarda la gestione del codice sorgente, mentre il terzo (“Pragmatic Automation”) si focalizza sulle varie procedure di automazione sul codice (compilazione, release e quant’altro).
NUnit è una piattaforma di open source specificatamente progettata per eseguire test su parecchi sistemi operativi e con diversi ambienti di sviluppo (non solo Visual Studio, ma anche SharpDevelop o Mono Develop, giusto per fare 2 esempi). Fornisce tutta una serie di “Assert” per verificare i risultati attesi dal proprio codice, e soprattutto consente di utilizzare un’interfaccia che tramite barre rosse e verdi (testi falliti e test con successo) da’ un’immediata visione su come stanno procedendo i test.
Nei primi 3 capitoli del libro viene spiegato, oltre ad un minimo di teoria dei test, anche come si usa questo tool e quali sono gli “Assert” più utili e raccomandabili. Gli autori, fortunatamente, non sommergono il lettore con lunghe tabelle riportanti tutte le varie opzioni di questa clausola, ma si limitano a spiegare come funzionano le più utilizzate ed importanti.
Gli esempi sono semplici, brevi e chiari, e non utilizzano caratteristiche sofisticate del C#. Viene data però molto importanza alla programmazione ad oggetti, e si presuppone che il lettore la conosca bene. Questa è comunque una base necessaria, dato che il Test Driven si basa e sfrutta molto le tecniche di ereditarietà, polimorfismo e incapsulamento. Lo scopo è chiaro: scrivere il meno possibile di codice, ottimizzato e generalizzato fino a dove è possibile.
Questa è la seconda edizione del libro, esattamente di un anno fa, e si riferisce alla versione 2.4 di NUnit, che introduce una variante della classica sintassi degli Assert (tipicamente Assert.IsNotNull, Assert.AreEqual e così via), scritta questa volta come “Assert.That”, ed nel prosieguo dei capitoli viene utilizzata solo questa (non è comunque difficile riportarla al “vecchio” stile).
Gli autori si soffermano, non solo sugli aspetti tecnici dei test, ma soprattutto sulla logica e sul perché vanno fatti, come anche su come decidere cosa testare e cosa no. Ci sono poi delle regole, abbastanza intuitive e sensate, da seguire, racchiuse nell’acronimo “CORRECT”, ovvero: Conformance, Ordering, Range, Reference, Existence, Cardinality e Time. Chi già ha avuto modo di impratichirsi con il Test Driven ritroverà con piacere molti concetti su cui ci si è soffermato e ragionato a lungo. Il quinto capitolo è tutto dedicato a loro, e alla fine presenta 6 brevi esercizi per ragionare su come implementare dei test in svariate circostanze. Le risoluzioni (a parole, niente codice) sono riportate in appendice. Anche nei capitoli sono presenti brevi esercitazioni o ragionamenti da fare: un semaforino posto a lato del testo avvisa il lettore di non procedere nella lettura fino a quando esegue quanto prescritto.
Il sesto capitolo tratta invece di un argomento altrettanto importante, l’utilizzo dei “Mock”, ovvero oggetti virtuali che simulano situazioni difficili o ininfluenti da testare, come possono essere l’accesso a database o al file system.
Gli ultimi 2 capitoli (nono e decimo) spiegano come implementare i test quando c’è di mezzo un interfaccia grafica di tipo Windows e di tipo Web. Per questi casi gli autori, oltre ovviamente a presentare esempi commentati sul come procedere, consigliano l’utilizzo di diversi tool (sempre gratuiti) per affrontare i test in questi campi spesso problematici (ma pur molto diffusi).
Questo piccolo libro (poco più di 200 pagine) può essere tranquillamente letto in un weekend o in un paio di serate. È molto discorsivo, si lascia leggere con piacere ed interesse, e non contiene enormi listati di codice da provare. Come anche altri libri sul Test Driven però, non sarà sufficiente una sola lettura, ma dovrà essere letto e riletto più volte man mano che si prende pratica e si creano i propri test. Tanti concetti e tante sfumature non vengono infatti colte alla prima lettura, ma sarà necessario ripassarci sopra più volte. Utilissimo poi il prospetto riepilogativo presente alla pagina 209 (in fondo al libro). Dato che è scaricabile (in pdf) dalla pagina web dedicata al testo, consiglio di stamparsela e tenerla bene in vista accanto al monitor: riporta tutti i concetti essenziali bene in vista.
Dal sito è possibile scaricare il codice sorgente utilizzato negli esempi ma, essendo di dimensioni ridotte ed abbastanza comodo da replicare, consiglio di riscriverlo passo per passo, in modo da prendere pratica (non porterà via tanto tempo). Oltre ad NUnit, scaricabile gratuitamente, consiglio anche di utilizzare un altro tool della stessa famiglia, ovvero NCover, che fornisce in forma grafica la “copertura” del proprio codice, per vedere se ogni ramo e riga delle proprie classi vengono intoccati (“coperti” appunti) da almeno un test.
Avendo poi Visual Studio 2008, si può mettere insieme il tutto e predisporre un ambiente adatto per impratichirsi con i test. Anche se non riportato tra i tool consigliati dagli autori, consiglio di provare TeamCity, un ottimo programma ricchissimo di funzionalità, tra le quali, oltre al code coverage (sia in percentuale che in numero di chiamate), anche numerose ed utilissime statistiche di ogni tipo.
In una delle appendici è riportata una ragionata bibliografia di 14 libri su cui approfondire gli argomenti (stranamente manca proprio il libro di Kent Beck).
Per chi è interessato, di questo libretto esiste l’identica versione per Java (con JUnit come tool di test).
PRO
Gli autori conoscono molto bene l’argomento, sanno come spiegare le cose e riescono ad infondere nel lettore la filosofia del “fare i test prima del codice”. Il libro si fa leggere, è sempre interessante, cattura l’attenzione e non è mai noioso. Il codice è perfettamente indentato, le righe sono numerate e le parole chiave più significative sono riportate in grassetto. Esemplare l’appendice A (“Gotchas”), dove sono riepilogate 10 regole base da seguire e da tener presente quando si impostano i test. Ottima rilegatura.
CONTRO
Ogni tanto ho riscontrato qualche leggero errorino nel codice, comunque nulla di preoccupante e facilmente evidenziabile. L’inglese non è semplicissimo: la presenza di parole dall’uso poco comunque obbliga a leggerlo con il dizionario a porta di mano (a meno che si sia madrelingua inglese).
Voto complessivo: 8/10
Lettore: Intermedio
Summary
Preface
1 – Cap. 1: Introduction
15 – Cap. 2: Your First Unit Tests
31 – Cap. 3: Writing Tests in NUnit
61 – Cap. 4: What to Test: The Right BICEP
73 – Cap. 5: Correct Boundary Conditions
93 – Cap. 6: Using Mock Objects
123 – Cap. 7: Properties of Good Tests
137 – Cap. 8: Testing on a Project
153 – Cap. 9: Design Issues
177 – Cap. 10: UI Testing
195 – App. A: Gotchas
203 – App. B: Resources
209 – App. C: Summary: Pragmatic Unit Testing
211 – App. D: Answer to Exercise
Titolo: Pragmatic Unit Testing in C# with NUnit (2nd Edition)
Autori: Andrew Hunt, David Thomas
Editore:Pragmatic
ISBN: 0-9776166-7-3
Pagine: 227
Prezzo: 29.95 $ (prezzo di copertina)
Data di uscita: Aug. 2007