Nei vari manuali di ingegneria del software esistono svariati modelli che descrivono il ciclo di vita di un software. Prendendo in considerazione il classico, e ormai obsoleto, modello a cascata di Royce possiamo trovare la seguente linea temporale: Analisi, Progettazione, Realizzazione, Manutenzione. Tutto ciò, se inserito all'interno di una linea temporale, diventa estremamente costoso in fatto di ore di lavoro, e quindi di costi, nella sua fase di manutenzione. Se paragonassimo la progettazione di un software, ad esempio, con la progettazione di una casa, ci accorgeremmo che mentre alla progettazione di una casa diventa precisa e sicura, mentre nel mondo software si danno come normali l'insorgenza di bug, le modifiche in corsa, l'imprecisione del disegno iniziale. Perchè tutto questo? La risposta più immediata che possiamo darci è che tutto ciò sia un difetto congenito del software, il quale nasce dal suo essere un prodotto complesso, astratto e poco rappresentabile.
Soluzioni al problema
Prendendo atto dai difetti sopra descritti proviamo ad andare a vedere quali soluzioni sono sorte per aggirare tali problemi: l'introduzione della programmazione ad oggetto (OOP); la creazione di controlli sofisticati nei compilatori e negli ambienti di run-time, come la tipizzazione delle variabili, la memoria gestita, la gestione strutturata delle eccezioni fino ad arrivare ai puntatori a funzione tipizzati di .Net (i delegate). L'eXtreme Programming può essere visto, sotto questo aspetto, come un nuovo metodo per la creazione di codice sicuro e controllato, anche se le caratteristiche opriginali dell'XP vanno ben oltre questa semplice, se pur importante, caratteristica. Kent Beck, il fondatore della XP Moviment, dice proprio che XP è un insieme di pratiche per lo sviluppo del software basate sui valori della semplicità, della comunicazione con il committente e tra i membri del team di sviluppo, del feedback e del coraggio.
Il classico pattern di sviluppo dellXP
Vediamo innanzitutto quali sono i principali punti di questa metodologia di programmazione:
- individuazione del problema;
- scomposizione del problema nelle sue unità fondamentali;
- creazione di set di test per ogni singola unità di codice;
- creazione vera e propria dell'unità di codice;
- testing attraverso i set di test;
- refactoring del codice.
Il processo di sviluppo del software, una volta arrivato a questo punto, di certo non termina qui, bensì viene ripreso e ripetuto più volte finchè non si arriva all'obiettivo per approssimazioni progressive.
I test
La principale novità di questa metodologia di sviluppo riguarda proprio i test che le singole unità devono superare. Un'unità, la quale corrisponde alla parte più elementare in cui può essere sudduvuso il progetto, risponderà alle esigenze del progetto solo e soltanto quando avrà superato tutti i test prefissati, e non quando riuscirà ad eseguire le proprie funzioni. Un esempio pratico per capire questo concetto, se siamo in riunione col nostro committente, il quale ci dice che il programma deve ritornare, dato il CAP, la città relativa con annessa la provincia, ecco nascere un primo test. Infatti il nostro committente ci sta dando un'indicazione su cosa il programma deve assolutamente restituire, e non di far funzionare il nostro codice in un qualche modo. Quindi, stando al nostro esempio, se noi dovessimo inserire come CAP 37100 il programma dovrà restituirci Verona e VR come provincia.
Il refactoring
Un'altra novità introdotta da questa pratica è senz'altro il refactoring, utilizzato per poter migliorare il design strutturale dell'applicazione. Tutti coloro che si affacciano solo ora al mondo della programmazione, o comunque programmano da poco tempo, si potrebbero chiede: ma perchè prevedere già una fase dove andrà modificata la struttura del programma invece di disegnarla già in modo corretto fin dall'inizio? La risposta è semplicemente che non sapremo mai fin da subito le specifiche del problema, sia da parte dell'analista sia da parte del committente. E comunque 99 volte su 100 il committente chiederà dei cambiamenti al programma in fase di posa dell'opera. Quindi ecco diventare importante prevedere anche questa fase. Tale fase, però, presenta un rovescio di medaglia: mettere mano all'architettura dell'applicazione porta con sè sempre quanche rischio di un non funzionamento. Ed ecco il motivo per cui è stato introdotto il coraggio come uno dei punti fondamentali dell'XP.
Per approfondire di più sul refactoring esistono diverse guide on-line, oppure basarsi sul manuale "Extreme Programming Adventure in C# - Ron Jeffries (Microsoft Professional)".
Emergono i primi bug
Prendendo in esame l'esempio di prima, Il nostro programma sta crescendo molto, e, come succede per ogni software di grandi dimensioni, anche il nostro programma riscontra i primi bug. Cosa fare adesso? Nel modello XP non ci interessa se il bug si sia riscontrato a causa del refactoring, di modifiche chieste dal committente, di un'errata codifica o di una codifica concorrenziale tra più sviluppatori. L'unica cosa che ci chiede il modello è scrivere un test che faccia fallire il programma, in modo da verificare il bug, quindi in seguito va corretto il codice in modo che il test vada a buon fine.
Riuscita e fallimento dei test: corollario alla regola generale
Generalmente, un test che fallisce alla prima esecuzione deve fallire sempre. Al contrario, un test che riesce al primo colpo deve passare sempre. Il presupposto che sta sotto a questa regola è che l'oggetto a cui vengono sottoposti i test deve avere uno stato consistente e certo. Ovviamente se il nostro test va a verificare l'algoritmo che esegue una somma tra dei numeri, lo stato consistente sarà sempre verificat. Al contrario, se il nostro test verifica un algoritmo che controlla il numero di file presenti all'interno di una cartella di un file system. Ovviamente in questo caso lo stato iniziale non è certo ma dipende dal contesto. Ovviamente questo è solo un esempio, tra l'altro risolvibile, con cui diventa problematico eseguire dei test. Pensiamo ad esempio un test da eseguire su un'istanza complessa, oppure su un Data Access Layer. Questi sono casi in cui lo stato iniziale non è mai certo.
Nunit
Venendo alla pratica, Nunit è senz'altro un ottimo prodotto free con cui eseguire dei test nei propri programmi. Scaricabile in allegato al suo codice sorgente, Nunit mette a disposizione esempi e una serie completa di test con cui si può sottoporre lo stesso Nunit. Una volta installato troveremo nel menu programmi un eseguibile (NUnit-GUI) e una serie di esempi che ci introdurranno all'utilizzo degli unit test.
Implementazione dei primi test
Creiamo un progetto semplice semplice per vedere come eseguire i nostri test. Creiamo una libreria di classi che esegua delle operazioni matematiche (che io per comodità chiamerò OperazioniMatematiche) con quattro metodi, che ovviamente saranno sottrazione, addizione, divisione, moltiplicazione.
Andiamo a sviluppare il metodo per la divisione:
{
return dividendo / divisore;
}
Fatto ciò non dobbiamo far altro che creare il nostro primo test. Possiamo inserire i nostri test anche in assembly esterni, in modo tale da non inserire del codice inutile all'interno del nostro progetto.creiamo quindi una nuova libreria di classi esterna al nostro progetto, inserendo come riferimento la nostra libreria delle operazioni matematice e un riferimento al framwork NUnit. Ora la nostra classe ha tutti i riferimenti necessari per poter eseguire i nostri test. Inseriamo quindi l'attributo TextFixture in testa alla classe
public partial class Form1 : Form
Fatto ciò possiamo creare il nostro test, anteponendo al metodo da testare l'attributo Test, per poi così poter istanziare la nostra classe OperazioniMatematiche ed impostare l'asserzione, che nel nostro caso, visto che 12/3 risulta 4, dovrà ritornare vero.
public void testaDivisione()
{
OperazioniMatematiche.operazioniMatematiche
div = new OperazioniMatematiche.operazioniMatematiche();
NUnit.Framework.Assert.IsTrue(div.divisione(12, 3) == 4);
}
Esecuzione dei test
Per eseguire i nostri test aprire dal menu programmi/nunit la nostra gui. Quindi dal menu file creare un progetto nuovo. Consiglio, per semplicità e uniformità, di salvare i nostri progetti nunit insieme ai progetti .net che stiamo testando. Una volta creato il nuovo progetto aggiungere l'assembly (che nel mio caso, visto che è un windows form, sarà un .exe, nel caso di una libreria di classi sarà una .dll) dal menu project/add assembly. Fatto ciò si esegue il tutto tramite il tasto run. Se il test andrà a buon fine comparirà un pallino verde nella traybar e la status bar sarà colorata di verde. Ne caso il test non vada a buon fine il tutto sarà di colore rosso con tanto della descrizione dell'errore.
Attributi e asserzioni
NUnit, oltre agli attributi utilizzati qui sopra, ne mette a disposizione altri, come:
- TestFixtureSetUp e TestFixtureTearDown, i quali indicano che il codice va eseguito rispettivamente prima e dopo qualunque altro test contenuto all'interno di una classe TestFixture.L'utilità di questi due attributi è abbastanza intuitivo: servono a creare l'ambiente consistente di cui necessitano i test per funzionare (es TextFixtureSetUp potrebbe creare un file con un certo contenuto su cui poi i vari test opereranno mentre TextTextureTearDown si occuperà di cancellare il file).
- ExpectedException, il quale indica che il test in oggetto deve sollevare un'eccezione, come ad esempio un test sulla divisione che attribuisca al divisore il valore 0 dovrà attendersi un errore del tipo System.DivideByZeroException.
Stesso discorso vale per le asserzioni, le quali possono essere del tipo condizione:
- IsTrue
- IsFalse
- IsNull
- IsNotNull
O del tipo confronto
- AreEqual (per confronti tra tipi valore)
- AreSame (Per confronti fra tipi riferimento)
Esiste inoltre Assert.Fall, il quale farà fallire il test senza il bisogno di verificare nessuna asserzione.
Conclusione
L'idea di mettere sotto controllo il codice attraverso altro codice è già di per se avvincente, ma il fatto che questa tecnica permetta veramente di avere un controllo così stretto sul codice dovrebbe convincere chiunque della bontà di tale metodologia.
Si conclude qua il nostro articolo sull'eXtreme programming. Se avete riscontrato delle difficoltà, se avete dei dubbi o suggerimenti per migliare l'articolo, o semplicemente avete trovato interessante l'articolo, lasciate un commento nel forum di MagisterInformatica nella relativa sezione.



