Elaborato Angelino Pasquale N46000090
Transcript
Elaborato Angelino Pasquale N46000090
Facoltà di Ingegneria Corso di Studi in Ingegneria Informatica Elaborato finale in Ingegneria del Software Stato dell'arte e valutazione di strumenti open source per il testing black box Anno Accademico 2012/2013 Candidato: Angelino Pasquale matr. N46/000090 Ai miei genitori , a mia sorella , ai miei angeli... Indice Introduzione 4 Capitolo 1. Principi e automazione del testing black-box 6 1.1 1.2 1.3 1.4 1.5 1.5.1 1.5.1.1 1.5.1.2 1.5.2 1.6 Obiettivi del testing di un prodotto software Fondamenti di progettazione di test case Valutazione del testing Principali attività di testing Testing black box Metodo delle classi di equivalenza (o delle partizioni) Suddivisione in classi di equivalenza Copertura delle classi di equivalenza: testing combinatoriale User Interface Testing Testing Automation Capitolo 2. Valutazione di strumenti open source per testing black box 2.1 2.1.1 2.1.2 2.2 2.2.1 2.2.1.1 2.2.2 2.2.3 2.2.4 2.3 2.4 Conclusioni Bibliografia JUnit Caratteristiche principali di JUnit JUnit 4 Selenium Selenium IDE Utilizzo di Selenium IDE Selenium RC Selenium WebDriver Selenium Grid Tobias Korat 6 7 7 8 9 11 11 12 13 14 15 15 16 18 21 21 22 24 26 26 27 29 31 32 III Stato dell'arte e valutazione di strumenti open source per il testing black box Introduzione Spesso si è portati a sottovalutare l'importanza del testing di un software per la sua natura di attività tipicamente "non costruttiva", anzi, in un certo senso distruttiva del lavoro effettuato in precedenza da chi ha sviluppato il sistema. In realtà, senza questa attività, un'applicazione di una qualunque azienda risulterebbe nella stragrande maggioranza dei casi inutile e/o non utilizzabile. E' attraverso il testing che vengono scoperti i difetti del prodotto e se ne mostrano i malfunzionamenti, ed è grazie ad esso che avviene la sua reale convalida. Con queste parole non si vuole di certo sminuire le fasi di progetto e realizzazione, senza le quali il software non esisterebbe affatto, ma si intende far comprendere il motivo per il quale, nella stima dei costi di un generico prodotto, il testing da solo occupi ben il 40% di essi. E questo non solo perché molte volte ha una durata ben più lunga di quanto ci si potesse immaginare, ma anche perché dovrebbe sempre iniziare dalle prime fasi di costruzione del sistema, con gli stessi sviluppatori che provano i componenti da loro creati, superando il conflitto di interessi e il senso di colpevolezza che sorge nel momento in cui ci trovano degli errori e comprendendo che è anche tramite il testing che un software può realmente divenire un prodotto di qualità. Questa trattazione interesserà in particolare una delle strategie di testing più significative, quella funzionale, che prova il sistema senza interessarsi di come questo è stato realizzato e tocca principalmente le fasi finali del processo di test, sebbene venga attualmente utilizzata spesso anche per i singoli componenti realizzati. Ci si immedesima pienamente nel cliente dell'applicazione, che infatti è molte volte coinvolto in modo anche attivo in questa procedura, proprio per mostrargli la validità del software e metterlo in condizioni di accettarlo, visto che alla fine sarà lui a doverlo utilizzare, e quindi testarlo con dati che non siano i suoi può aiutare solo relativamente a verificarne la correttezza. 4 Stato dell'arte e valutazione di strumenti open source per il testing black box Risulta chiaro, però, come attualmente l'effettuare questa attività in modo manuale sia alquanto gravoso e, inoltre, può farne salire ancora i già considerevoli costi. Ecco il motivo per il quale si cerca di automatizzarla il più possibile mediante l'ausilio di strumenti che consentano non solo di ridurre le fatiche e i tempi del processo, ma anche di eseguirlo in maniera ottimale, cosa che non sarebbe possibile nella maggioranza dei casi con il solo intervento umano. In particolare, al giorno d'oggi l'attenzione generale è parecchio orientata ai benefici offerti, non solo in questo campo, da una specifica classe di strumenti, e cioè quelli open source, letteralmente "a sorgente aperto", che, se per un normale utente richiamano solo il fatto di essere gratuiti, per i programmatori e sviluppatori della rete rappresentano un prodotto in evoluzione continua, a cui loro stessi possono far riferimento e contribuire, collaborando tra loro anche se lontani. Verrà quindi illustrato, nel corso della trattazione, il funzionamento di alcuni validissimi strumenti open source per eseguire testing black box, che non avranno quelle grandi potenzialità che forse possiedono gli equivalenti commerciali allo stesso scopo, ma sicuramente con la loro semplicità d'uso e con le funzionalità essenziali offerte, non lasciano che questo pesi troppo su chi li utilizza, motivo che ne ha decretato nel corso degli anni la rapida diffusione e l'innegabile successo. 5 Stato dell'arte e valutazione di strumenti open source per il testing black box Capitolo 1 Principi e automazione del testing black-box In questa prima parte verranno richiamati i concetti e le definizioni principali di software testing, focalizzando l'attenzione sulla strategia black box e sul come essa viene, in generale, attuata nell'ambito del collaudo del software; il discorso verrà, poi, esteso brevemente al caso di testing combinatoriale e di testing di sistemi interattivi (in particolare di interfacce utente, UI). Infine, si cercherà di approfondire la problematica dell'automazione delle attività di testing funzionale, evidenziandone le caratteristiche peculiari, che saranno, quindi, alla base dell'utilizzo degli strumenti open source valutati in seguito. 1.1 Obiettivi del testing di un prodotto software Qualsiasi processo aziendale con l'obiettivo di realizzare un sistema software prevede diverse attività produttive nelle quali, per interpretazione inesatta dei requisiti del prodotto o anche per errato utilizzo degli strumenti a disposizione, si tende, sin dai primi stadi di sviluppo, a commettere errori, che si manifesteranno nel prodotto finale come veri e propri difetti dello stesso, e che non gli consentiranno di agire, in esecuzione, secondo le aspettative (provocando un malfunzionamento). E' a causa di questa incapacità umana di operare e comunicare in modo perfetto che la realizzazione di un qualunque sistema software è affiancata da un'attività di garanzia di qualità del prodotto, che viene provato in un certo numero di situazioni rappresentative, accertando, prima del rilascio al cliente, che si comporti come previsto (test di convalida) e che sia quanto più possibile privo di difetti (test dei difetti). Il testing risulta essere dunque un'attività sperimentale di verifica del software, poichè gli errori dello stesso vengono ricercati osservandone il comportamento e confrontandolo con quello stabilito in fase di specifica, a differenza di quanto viene fatto, invece, con l'attività analitica di ispezione del codice e della documentazione di progetto ad esso relativa, basata sul semplice studio di modelli statici del sistema. 6 Stato dell'arte e valutazione di strumenti open source per il testing black box Può anche darsi che un difetto nel codice dell'applicazione produca un malfunzionamento solo se viene utilizzato un particolare compilatore o interprete, oppure solo su una determinata piattaforma di esecuzione. Pertanto, potrebbe essere necessario collaudare il software su varie piattaforme e ambienti di sviluppo. 1.2 Fondamenti di progettazione di test case Per poter testare il software per scoprire (e quindi poi correggere) quanti più difetti possibili prima di fornirlo al cliente, è necessario progettare una serie di casi di test, ossia particolari scenari di esecuzione con specifiche combinazioni dei valori d'ingresso al sistema, che abbiano un'elevata probabilità di far esibire malfunzionamenti. Questa attività va però eseguita in maniera disciplinata e sistematica e utilizzando tecniche ben precise, per evitare che il testing del prodotto diventi troppo lungo o gravoso. Il tempo e le risorse a disposizione di chi collauda il software sono infatti limitati, perciò è necessario che ogni test case distinto sia né troppo semplice né troppo complesso, e che abbia uno scopo, seppur in modo sottile, diverso da quello degli altri appartenenti alla stessa test suite (insieme dei casi di prova progettati). Per verificare che il comportamento osservato del prodotto sia quello previsto (dove la conoscenza di quest'ultimo risulta essere la prima condizione che deve essere soddisfatta prima di poter effettuare un qualsiasi test), il software deve dunque essere provato in un certo numero di situazioni rappresentative che ne garantiscano un operato accettabile anche nei contesti di funzionamento non presi sotto esame, data l'impossibilità di generare tutte le diverse possibili configurazioni dei dati di ingresso e, quindi, di testarlo in tutte le sue condizioni operative. Difatti, il successo di un test dei difetti deriva dalla sua capacità di evidenziare gli errori commessi nello sviluppo del sistema software, ma nulla di quanto viene fatto durante quest'attività assicura che lo stesso sistema sia privo dei difetti suddetti, proprio a causa della già menzionata non attuabilità, in tempi ragionevoli, di un testing realmente esaustivo. 1.3 Valutazione dell'attività di testing Durante le fasi di progettazione e sviluppo di un prodotto, l'ingegnere del software deve sempre 7 Stato dell'arte e valutazione di strumenti open source per il testing black box tenere in grande considerazione il fatto che questo sistema dovrà poi essere "collaudato" da chi di dovere, e per questo è necessario che il suo lavoro sia mirato anche a facilitare le future prove di esecuzione che verranno effettuate. Allo stesso modo, chi progetta i test case deve fare in modo che questi abbiano in sé le caratteristiche necessarie ad individuare il maggior numero di errori del sistema, ma col minimo sforzo. E' per questo che il test dovrebbe essere sempre adeguato, con casi di test significativi invece che numerosi; questo aiuterà anche a far sì che i suoi risultati siano il più possibile affidabili e precisi, riuscendo a isolare gli errori che verranno poi corretti in una successiva fase di debugging. Questa precisione dipende in gran parte, però, anche dalla stessa accuratezza e accessibilità con cui sono state formulate le specifiche del sistema, visto che la progettazione dei casi di prova è in gran parte basata proprio sui risultati dell'ingegneria dei requisiti. In definitiva, si deve, quindi, cercare di raggiungere un giusto compresso tra numero di difetti scoperti e numero di test case condotti, per evitare di eseguire un test troppo costoso o, peggio, inutile, soprattutto quando non si hanno a disposizione degli strumenti automatici a supportare le attività. 1.4 Principali attività di testing Come si è già avuto modo di precisare, il testing dovrebbe essere un'attività tutt'altro che disorganizzata. In particolare due sono le fasi fondamentali che dovrebbero esistere in un qualsiasi processo di verifica software: il test delle unità e il test del sistema. E' facile rendersi conto di come questi due processi siano inevitabilmente collegati tra di loro: i difetti dei componenti volutamente ignorati o sfortunamente non evidenziati durante i primi test, saranno, a volte anche "brutalmente", scoperti durante il test del prodotto completo. Il test delle unità è il processo con cui vengono testati i singoli componenti (dotati di funzionamento autonomo) di un sistema. E' un test dei difetti, che mette in luce gli errori commessi nelle fasi di sviluppo delle varie parti del software. Nella maggior parte dei casi sono gli stessi sviluppatori a testarle, iniziando il progetto del testing già nella fase di sviluppo. Se da un lato il collaudo risulta semplificato, poiché chi ha creato il componente ne conosce vincoli e struttura, e 8 Stato dell'arte e valutazione di strumenti open source per il testing black box quindi può più facilmente verificare che questi soddisfino i loro requisiti iniziali, dall'altro lo sviluppatore è evidentemente di parte, e tende a giustificare gli errori che lui stesso ha commesso, evidenziando meno i difetti del software. I vari moduli prodotti verranno poi integrati, costruendo il sistema complessivo, ed un team indipendente di testing sarà responsabile dell'attuazione di un vero e proprio test del sistema, con obiettivo la verifica della correttezza dell'intero software. Questa fase prevede innanzitutto la costruzione del sistema a partire dai vari moduli; si verifica che vengano richiamati correttamente, che trasferiscano i dati nei tempi giusti e che, quindi, lavorino effettivamente assieme. Viene detta "test di integrazione" e in pratica viene effettuata per cercare errori nel sistema visto come insieme delle sue parti, ossia nell'organizzazione dei componenti e nella loro cooperazione. Successivamente avviene il test della release, che ha come obiettivo la convalida di una versione del sistema di prossima consegna agli utenti (se questi ultimi sono coinvolti attivamente nella verifica si parla proprio di test di accettazione della release), mostrando che questa soddisfi i suoi requisiti e sia affidabile. Se il sistema presenta problemi, questi verranno comunicati poi agli sviluppatori, che avranno premura di effettuare il dovuto debugging dell'applicazione. Questo test è solitamente derivato dalle specifiche del software, che viene trattato come una "scatola nera" il cui comportamento è descritto solamente dall'applicazione di dati di ingresso e dall'esame delle uscite prodotte. Per questo motivo viene detto test black box, o funzionale, in quanto, a differenza del test strutturale (detto infatti white box), l'attenzione viene rivolta alle funzionalità che il singolo componente o il sistema dovrebbe offrire, senza curarsi di come queste siano state effettivamente realizzate. 1.5 Testing black box Testare un software o una sua parte identificandolo come una scatola nera significa verificare che svolga effettivamente le funzioni che dovrebbe e che lo faccia in modo corretto. Non ci si 9 Stato dell'arte e valutazione di strumenti open source per il testing black box preoccupa della sua struttura interna, dell'implementazione e di come abbiano lavorato i programmatori. Si accede al software solo tramite l'interfaccia utente oppure tramite altre interfacce di comunicazione tra processi. Anche in questo caso, infatti, il lavoro dei testers (che spesso appartengono a un'organizzazione diversa da quella che ha sviluppato il software) non può non dipendere da un altro tipo di lavoro, e cioè quello eseguito da chi si è occupato della specifica dell'applicazione. Il testing black box si concentra sui requisiti funzionali del software: più preciso è stato il modo in cui questi sono stati formulati, più precisi potranno essere i casi di test derivati da essi e la valutazione dei loro risultati. Inoltre, nel caso in cui il codice sorgente o la documentazione di progetto siano da mantenere come "segreti aziendali", il fatto di poter far effettuare questo collaudo anche a persone esterne all'azienda, risulta essere un indiscutibile vantaggio, così come la possibilità di affidarsi anche a programmatori che non conoscano gli aspetti interni del software o che non siano così esperti, e che quindi sono più facili da trovare (e anche meno costosi). Chi effettua questi test invia al componente o al sistema degli input riconosciuti, dopo una sistematica attività di selezione, come ad alta probabilità di successo, ossia di scoperta di difetti nel software, basandosi magari sull'esperienza o semplicemente sul giudizio. Una volta stimolato il sistema, vengono esaminati gli output forniti e se questi non concordano con quanto previsto nella progettazione del test case, allora è stata rilevata la presenza di difetti nel software. 10 Stato dell'arte e valutazione di strumenti open source per il testing black box Si dovrebbe anche cercare di testare per primi i moduli del sistema che si prevede verranno maggiormente utilizzati, così da concentrare su di essi gli sforzi maggiori, lasciando alla fine il testing di quelle parti dell'applicazione, la cui esecuzione interesserà solo scenari di utilizzo eccezionali, anche se, ovviamente, nulla assicura che non siano proprio quelle le funzionalità ad essere affette da errori. 1.5.1 Metodo delle classi di equivalenza (o delle partizioni) Uno degli approcci più utilizzati per la progettazione di test case nel testing black box è sicuramente quello delle partizioni o classi di equivalenza, basato sulla diffusa tendenza dei sistemi software a comportarsi, in molti scenari d'esecuzione, nello stesso modo, a fronte di ingressi che presentano una qualche correlazione o caratteristica comune. C'è da precisare subito, però, come questa attitudine, di forte valenza in molti altri settori costruttivi, nel campo dell'ingegneria del software debba essere trattata con cautela, poiché spesso piccolissime differenze, nei dati di input o nelle condizioni dell'ambiente operativo, possono provocare comportamenti imprevedibili e fortemente diversi tra loro, non mostrando quindi quella continuità che semplificherebbe notevolmente l'attività di testing e lo studio del sistema. 1.5.1.1 Suddivisione in classi di equivalenza Con questo approccio, quindi, il dominio dei dati d'ingresso viene suddiviso in classi dalle quali verranno derivati i casi di prova da sviluppare, riducendo notevolmente il numero di questi ultimi necessario a dedurre il generico errore del sistema. I test case vengono, difatti, selezionati in modo da provare simultaneamente il maggior numero di attributi di una classe, basandosi in gran parte sulle specifiche del sistema, ma anche sull'esperienza. Tramite questi test è possibile constatare se il software si comporta come dovrebbe e se gestisce in modo corretto anche gli input non validi. Una possibile partizione di equivalenza è, infatti, proprio quella in ingressi validi e non validi per il sistema. C'è una cosa però da tener presente: l'appartenenza ad una classe piuttosto che ad un'altra dipende fortemente anche dallo stato interno 11 Stato dell'arte e valutazione di strumenti open source per il testing black box dell'applicazione, che spesso non è facile determinare in modo ideale. In generale, una condizione d'ingresso sulla quale possono essere definite la classe di equivalenza di valori validi e quelle di valori non validi, può essere uno specifico valore numerico, un intervallo di valori, un insieme discreto di valori correlati tra loro oppure una condizione booleana. Un approccio più sistematico potrebbe prevedere anche la distinzione della stessa classe valida in più classi che dettagliano diverse casistiche di esecuzione, o ancora considerando quei valori atipici o di confine che di solito vengono ignorati da chi testa il software, ma che spesso sono anche la causa principale dei fallimenti del sistema, durante la loro elaborazione. 1.5.1.2 Copertura delle classi di equivalenza: testing combinatoriale Una volta definite le suddette classi, c'è da decidere quale debba essere la test suite che consenta di coprirle tutte. Anche in questo caso, l'ideale sarebbe trovare il giusto compromesso tra numero di casi di test e quantità di scenari testati (che consentano di rilevare malfunzionamenti). In generale comunque si può decidere di minimizzare lo sforzo di esecuzione del testing, con pochi test case, ma nei quali compaia almeno una volta ogni classe di equivalenza, oppure cercare di generare tutte le possibili combinazioni delle classi in cui è stato suddiviso il dominio d'ingresso. Si parla in questo caso di testing combinatoriale, che produce, a partire da tutte le classi di equivalenza, quindi valide e non valide, tutti i possibili casi di test ottenuti combinando le suddette, anche se alcuni, per come è stata progettata e realizzata l'applicazione e la sua interfaccia utente, 12 Stato dell'arte e valutazione di strumenti open source per il testing black box risulteranno non esercitabili, ad esempio se l'assegnazione di un certo valore di una particolare classe ne impedisce l'inserimento di un altro. Con questa tecnica si stima vengano riscontrati più del doppio dei difetti della normale copertura delle classi, e quindi una maggiore affidabilità e qualità del test, che contribuiscono, come si può immaginare, ad aumentare il livello di conformità dell'implementazione del prodotto alle sue specifiche. Di contro però l'efficienza del test è sensibilmente ridotta e difficilmente questa tecnica risulterebbe concretizzabile senza un valido supporto. Esperimenti industriali hanno però dimostrato che i test cases appartenenti a una test suite molto grande spesso presentavano un livello molto alto di similarità, ed alcuni di essi in pratica corrispondevano alla stessa sequenza di esecuzione di metodi, semplicemente con parametri differenti o operazioni tra loro simili. Produrre questi test case in maniera manuale sarebbe quindi stata un'attività assolutamente ripetitiva. Ecco il motivo per il quale la tecnica combinatoriale è risultata molto più utile se attuata in condizioni di test automatizzato, attraverso tool di collaudo come gli strumenti open source Tobias oppure Korat (per strutture più complesse) che verranno illustrati brevemente nel seguito della trattazione. 1.5.2 User Interface Testing Se un software è composto da diverse unità, queste interagiscono tra loro mediante delle interfacce, il cui collaudo risulta fondamentale, poiché l'esistenza di errori nella collaborazione tra gli elementi influenza il corretto funzionamento dell'intero sistema. Anche questo test delle interfacce è tipicamente eseguito in maniera black box, e in particolare quello di interfacce utente (UI), che viene effettuato provando i diversi possibili scenari di interazione utente-applicazione. Potrebbe essere necessario avere a disposizione un modello che descriva queste interazioni, e il più comunemente utilizzato è di sicuro quello come macchina a stati, con ingressi, rappresentati da eventi sull'interfaccia, che scatenano le diverse transizioni associate alle sollecitazioni-utente degli elementi caratteristici delle user interfaces, ovvero finestre e relativi widget. Esistono degli strumenti però che consentono di progettare test suite per le UI anche a prescindere da un modello formale, come quello descritto, delle stesse; uno di questi è il framework Selenium per le applicazioni web, che verrà ripreso e analizzato anch'esso in seguito, e che rappresenta un esempio di, come già accennato più volte, sia possibile utilizzare tools automatici a supporto della 13 Stato dell'arte e valutazione di strumenti open source per il testing black box progettazione ed esecuzione di test suite per il software. 1.6 Testing Automation E' facile comprendere come anche nel campo del software testing, così come accaduto in moltissimi altri settori industriali e sociali, l'automazione, con la sua capacità di ridurre all'essenziale la necessità dell'intervento umano, abbia quindi portato innumerevoli benefici. Non solo consente di ottimizzare tempi e costi riguardanti l'esecuzione di quelle attività presenti molto spesso nel processo di realizzazione e quindi ripetitive, ma semplifica anche quelle troppo ardue e faticose. Gli strumenti tecnologici addetti a queste operazioni offrono poi, senza dubbio, maggiore sicurezza riguardo la corretta concretizzazione delle stesse, rispetto ovviamente all'operato umano, che, anche in questo caso, ancor più delicato proprio perché finalizzato alla ricerca dei difetti del software, non è infallibile e non può quindi fornire quella certezza di essere stato portato a termine (sembra un paradosso) senza errori. In pratica, un testing compiuto sulla base del solo giudizio dell'uomo, può non riuscire a scovare i difetti del sistema, il che di sicuro non ne migliora la qualità, ed è per questo che gli strumenti automatici consentono di controllare il funzionamento del software offrendo maggiori garanzie circa la sua correttezza, e permettono inoltre di farlo in modo molto più veloce. Inoltre lo stesso test, a seguito di modifiche, può essere riutilizzato molto più facilmente, e questo è un vantaggio che, visti i già citati ed elevati costi dell'attività di testing, non deve essere affatto trascurato. 14 Stato dell'arte e valutazione di strumenti open source per il testing black box Capitolo 2 Valutazione di strumenti open source per testing black box In questa seconda sezione, come annunciato, vengono presentati alcuni dei molti tools open source disponibili per effettuare test, come detto, "a scatola nera". Si parte con il colosso nel campo dello unit testing JUnit, il cui impatto sull'automazione di testing funzionale è stato tale da influenzare la maggior parte degli strumenti sviluppati negli anni successivi. Come si vedrà lo stesso Selenium, utilizzato per il collaudo di applicazioni web e anch'esso illustrato nel seguito, prevede, infatti, la possibilità di integrare i risultati ottenuti con il suddetto framework. Infine, vengono presentati brevemente due ulteriori strumenti nel caso si voglia adoperare un approccio combinatoriale: Tobias e Korat, quest'ultimo basato sul testing di strutture dati anche complesse. 2.1 JUnit Nell'ambito del testing di unità tramite un approccio black box, lo strumento che ad oggi risulta essere quello cui la maggior parte degli ingegneri del software fanno riferimento è senz'altro il framework JUnit. Questo appartiene alla famiglia di frameworks per lo unit testing xUnit, che ebbe origine dal framework SUnit, sviluppato da Kent Beck per il linguaggio di programmazione SmallTalk e di cui rappresenta praticamente l'evoluzione. Junit risale ormai al 1997 ed è frutto del lavoro dello stesso Beck insieme a Erich Gamma, ed è uno strumento Java-oriented, ma, visti i risultati positivi ottenuti, ne sono state scritte diverse alternative per molti altri linguaggi di programmazione come C++ (CPPUnit), JavaScript (JSUnit) e così via... L'ultima release temporale di JUnit è JUnit 4 (in particolare la versione 4.11 del 14 novembre 2012), contenuta nel package org.junit, che ha introdotto alcune interessanti novità rispetto alle precedenti, residenti invece nel package junit.framework, cercando di essere sempre più in linea con le esigenze dei testers e di soddisfarle nel modo migliore possibile. La raccolta .jar di classi Java che costituiscono JUnit può essere controllata esplicitamente scaricandola dal sito ufficiale e aggiungendola al progetto Java realizzato, ma diversi ambienti di 15 Stato dell'arte e valutazione di strumenti open source per il testing black box sviluppo, come Eclipse o NetBeans, permettono di usare una versione di JUnit integrata nello stesso IDE come plug-in, senza bisogno di ulteriori installazioni, rendendo il già semplice utilizzo del framework ancora più immediato. 2.1.1 Caratteristiche principali di JUnit Come già si è avuto modo di far intendere, la forza di JUnit sta nella sua enorme semplicità, caratteristica che nel tempo ha fatto sì che un gran numero di frameworks sviluppati si poggiassero su di esso e sulla sua struttura., il cui elemento di base è sicuramente il già approfondito concetto di caso di test, qui rappresentato da una vera e propria classe Java, una per ogni classe da testare, che estende quella fondamentale di libreria chiamata TestCase. Avere delle classi di test separate dal software reale costituisce un primo indiscutibile vantaggio dell'utilizzo di JUnit, poichè in questo modo il programma non viene ulteriormente appesantito da questo codice, che potrebbe non solo creare conflitti di vario genere, ma che per giunta una volta terminato il testing dovrebbe anche essere rimosso, con conseguente ulteriore spreco di tempo e risorse. Ad ogni modo, ogni classe di test JUnit contiene metodi che identificano le diverse situazioni da provare e il cui nome, per convenzione, deve iniziare con il prefisso test per fare in modo che siano riconosciuti come tali. Ad esempio: public void testOperation( ) {...} JUnit assume, inoltre, che tra tutti i metodi di test non debba esserci alcun tipo di dipendenza, per non falsare o corrompere i risultati degli stessi. Questo aspetto di JUnit è purtroppo riscontrabile anche nello stesso concetto di comunicazione fra classi diverse. Infatti, il framework non risulta essere un utile supporto quando i malfunzionamenti di una unità sono dovuti alla sua integrazione con altri componenti del progetto. Oltre a questi metodi, le classi di test ne contengono altri due di uso condiviso setUp e tearDown, che vengono chiamati rispettivamente prima e dopo ogni metodo di test della classe, e sono utilizzati per predisporre e concludere l'esecuzione di ogni test, istanziando oggetti, aprendo o chiudendo la connessione a un database e così via... 16 Stato dell'arte e valutazione di strumenti open source per il testing black box Ma come fare per valutare i risultati di un test? JUnit mette a disposizione, a questo proposito, ulteriori metodi chiamati asserzioni, anche questi identificati da un prefisso speciale, assert, che verificano il comportamento (o lo stato) dell'unità sotto test e permettono di specificare tra l'altro anche il risultato atteso e un messaggio di errore da visualizzare nel caso questo non rispecchiasse quello attuale; in questo caso l'asserzione risulta falsa e il test case è fallito (è stato trovato un malfunzionamento). Utilizzare molte e diverse asserzioni può anche aiutare il tester ad avere indicazioni da mettere in pratica nella futura operazione di debugging. Le asserzioni più utilizzate sono riassunte nella seguente tabella: Statement Description fail(String) Let the method fail. Might be used to check that a certain part of the code is not reached. Or to have failing test before the test code is implemented. assertTrue(true) / assertTrue(false) Will always be true / false. Can be used to predefine a test result, if the test is not yet implemented. assertTrue([message], boolean condition) Checks that the boolean condition is true. assertsEquals([String message], expected, actual) Tests that two values are the same. Note: for arrays the reference is checked not the content of the arrays. assertsEquals([String message], expected, actual, tolerance) Test that float or double values match. The tolerance is the number of decimals which must be the same. assertNull([message], object) Checks that the object is null. assertNotNull([message], object) Checks that the object is not null. assertSame([String], expected, actual) Checks that both variables refer to the same object. assertNotSame([String], expected, actual) Checks that both variables refer to different objects. Figura 2.1 – Asserzioni di JUnit Le classi di test JUnit rappresentano, quindi, uno strumento sistematico per il test delle varie unità del software. Spesso i progetti ne includono però un numero così grande che potrebbe non solo rendere il codice piuttosto disordinato, ma anche singolarmente sottrarre tempo prezioso per la loro esecuzione. Ecco perchè JUnit fornisce la concretizzazione del meccanismo proprio dell'ingegneria del software di raggruppare più casi di test in un'unica test suite, la cui esecuzione implica quella automatica, in ordine arbitrario, di tutti i test in essa contenuti. Qui riportato un piccolo esempio di codice per una generica TestSuite: public class AllTests extends TestSuite { public static TestSuite suite( ) { 17 Stato dell'arte e valutazione di strumenti open source per il testing black box TestSuite suite = new TestSuite("All!"); suite.addTestSuite(MyTestCase.class); suite.addTestSuite(AnotherTestCase.class); return suite;} } 2.1.2 JUnit 4 Tutti gli elementi sopra accennati con le loro convenzioni costituiscono lo scheletro di base di un test JUnit. Con l'avvento di una nuova release del framework, si è cercato però di rendere ancor più immediata la scrittura delle classi di test, in particolare tramite un meccanismo che consentisse di identificare in modo evidente la natura dei diversi metodi. Sono state introdotte quindi le annotazioni (divenute disponibili con il Java Development Kit versione 1.5), con le quali ad esempio non è più necessario che i metodi di collaudo abbiano il nome che cominci con "test", ma il framework eseguirà ogni metodo annotato come @Test (anche se devono comunque restare void e senza parametri). Anche i metodi setUp e tearDown sono sostituibili con metodi annotati rispettivamente come @Before e @After, e inoltre non è più necessario che le classi di test ereditino dalla classe TestCase, anche se è possibile che vengano eseguite correttamente anche classi scritte per una versione precedente del framework. A questo punto però può giustamente sorgere il dubbio sul come vengano invocate le asserzioni se le classi di test non estendono più TestCase. La risposta è presto data: grazie agli import statici di Java 5, il problema non si pone e tutto può restare come è stato definito con una precedente versione, senza bisogno di modificare il codice dell'asserzione: import static org.junit.Assert.* . Altre annotazioni possono essere utilizzate per: quei metodi che devono essere eseguiti prima o dopo tutti i test contenuti in una classe, marcati rispettivamente con @BeforeClass ed @AfterClass (devono essere statici); per indicare metodi che il framework deve, almeno per il momento, ignorare nell'esecuzione (che nelle precedenti versioni sarebbero stati quelli che non iniziavano per "test"), 18 Stato dell'arte e valutazione di strumenti open source per il testing black box marcandoli semplicemente con @Ignore e facendo così in modo che questi possano in seguito essere re-inclusi nel test senza grosse difficoltà; per realizzare una test suite in modo ancor più rappresentativo, con @SuiteClasses({classi di test}), di cui predisporre l'esecuzione, ad esempio con @RunWith(Suite.class), dove Suite è uno dei possibili test-runners, incluso in JUnit. Di seguito sono riportati, a confronto, due semplici frammenti di codice (di esempio) che mettono in evidenza alcune delle suddette differenze tra le due versioni del framework: import import import import static org.junit.Assert.*; org.junit.After; org.junit.Before; org.junit.Test; import junit.framework.TestCase; public class TestBlackBox extends TestCase { public class TestBlackBox { protected void setUp() throws Exception{} @Before public void initialize() throws Exception{} protected void tearDown() throws Exception{} @After public void finalize() throws Exception{} @Test public void blackboxMethod() { fail("Not yet implemented"); } public void testBlackBoxMethod() { fail("Not yet implemented"); } } } Figura 2.2 – Codice JUnit 4 (a sinistra) e JUnit 3.8 a confronto 2.1.3 Esecuzione dei test con JUnit Due sono le possibili strade che possono essere percorse per poter eseguire un test tramite il framework JUnit. La prima è quella di utilizzare del codice Java standard. In particolare la classe org.junit.runner.JUnitCore fornisce il metodo runClasses( ) che consente di eseguire una o più classi di test. Come parametro di ritorno otterremo un oggetto del tipo org.junit.runner.Result che può essere utilizzato per recuperare informazioni sull'esito dei test. Le classi apposite di cui JUnit poi dispone sono junit.textui.TestRunner (su console) oppure junit.swingui.TestRunner (grafico). Basta aprire il command prompt, posizionarsi sulla cartella ed eseguire $java -cp junit.jar. Per far questo però, come si è già avuto modo di far notare, la libreria JUnit deve essere aggiunta al classpath del nostro progetto Java. 19 Stato dell'arte e valutazione di strumenti open source per il testing black box La seconda è invece più semplicemente utilizzare ambienti integrati come Eclipse, che fornisce anche supporto alla creazione dei test e, soprattutto, alla valutazione dell'esito degli stessi, verificando se il test ha avuto successo (ossia non sono stati trovati difetti, cosa che come è stato precisato più volte, però, è l'esito negativo del testing), se sono stati rilevati malfunzionamenti (viene lanciata una junit.framework.AssertionFailedError e bisogna rivedere il codice dell'oggetto del test) oppure se ci sono stati degli errori (può darsi che debba essere rivisto anche il test stesso). La barra che compare nella finestra di Eclipse rende ancor più evidente l'esito del test, poichè risulterà verde solo se tutti i test hanno successo. E' presente, infine, come si può vedere in figura, anche una Failure Trace, che fornisce informazioni sul tipo di errore o malfunzionamento verificatosi. Figura 2.3 – Esito con successo di un test JUnit in ambiente Eclipse Figura 2.4 – Esito con fallimento di un test JUnit in ambiente Eclipse Figura 2.5 – Esito con errori di un test JUnit in ambiente Eclipse 20 Stato dell'arte e valutazione di strumenti open source per il testing black box Tutto questo rende, quindi, JUnit ancora più rapido e semplice da adoperare, con un'interfaccia assolutamente user friendly, tanto da divenire ad oggi uno dei principali e più utilizzati strumenti di unit testing esistenti. 2.2 Selenium Selenium è un framework di software testing consistente in una suite di tools utilizzati per automatizzare il collaudo black box di web applications (in particolare per test di accettazione), su svariate piattaforme. Sono, infatti, supportati i più moderni e conosciuti browsers web e può essere eseguito su molti sistemi operativi come Windows, Linux e Mac OS. L'ultima release stabile di Selenium, la versione 2.25, è stata rilasciata a Luglio 2012. Originariamente sviluppato nel 2004 da Jason Huggins, nel corso del tempo Selenium è diventato sempre più popolare e viene oggi utilizzato da utenti e organizzazioni per testare in modo automatico sia la GUI (interfaccia utente grafica) che le funzionalità di un'applicazione, con l'indiscutibile vantaggio di mantenere l'integrità di quest'ultima sia durante che dopo lo sviluppo, ma consente anche di eseguire test di compatibilità del browser. E' possibile creare test tramite Selenium in due modalità: la prima è quella di generarli in automatico tramite uno dei tools forniti, ossia l'ambiente Selenium IDE. La seconda è quella, invece, di progettarli manualmente, utilizzando le client API messe a disposizione per molti linguaggi di programmazione. 2.2.1 Selenium IDE Selenium IDE è implementato come un'estensione del browser Mozilla Firefox, per cui è di facile installazione e permette di testare le applicazioni con l'approccio record & playback, basato sul memorizzare la sequenza di azioni effettuate da un tester per poterle poi eseguire nuovamente in modo autonomo, senza bisogno però di conoscere alcun linguaggio di scripting. Questo metodo rende il tool adatto ad effettuare anche eventuali test di regressione, a seguito della modifica di alcune funzionalità del sistema, con il solo svantaggio di dover riscrivere i test se questi risulteranno a un certo punto non più validi. I test possono essere salvati in diversi formati per il loro riuso con altri frameworks, ma 21 Stato dell'arte e valutazione di strumenti open source per il testing black box normalmente sono registrati in Selenese, il linguaggio di scripting speciale di Selenium, che fornisce i comandi in formato HTML per eseguire diversi tipi di azioni in un browser e per recuperare dati dalla pagina web. La forza di Selenium IDE risiede sicuramente nella sua estrema facilità di cattura e di successivo replay dei test, mettendo a disposizione dei collaudatori l'autocompletamento dei comandi più comuni (così da risparmiare tempo) oltre che la possibilità di editare a mano i propri test. Viene fornito, inoltre, anche un primo supporto al debugging, compreso l'inserimento di breakpoints. L'intera test suite può, quindi, essere prodotta in maniera quasi completamente automatica, garantendo in ogni caso il controllo completo sull'esecuzione dei vari test case, e con la possibilità aggiuntiva di ottenere un report completo su quelli terminati con successo e su quelli falliti, corredato da informazioni utili sui warnings e sugli errori rilevati. 2.2.1.1 Utilizzo di Selenium IDE Dopo averlo scaricato dal sito ufficiale della suite e installato in modo semplice come una qualsiasi altra estensione, Selenium IDE risulta automaticamente integrato in Firefox e subito a disposizione dell'utente nel menu del browser, tra gli Strumenti di sviluppo web. L'ultima versione attualmente rilasciata è quella 1.10.0 del 20 dicembre 2012. Il tool si mostra presto di utilizzo intuitivo ed immediato anche per i non programmatori, presentando un'interfaccia molto semplice per creare intere test suite, composta tra l'altro da una finestra nella quale, man mano che l'azione di record prosegue, vengono memorizzati in una tabella tutti i comandi inviati (vista Table) e generato il codice corrispondente in Selenese (vista Source). La registrazione dei comandi comincia subito, una volta che il tool viene lanciato, memorizzando le interazioni dell'utente con il browser e riportandole nella suddetta tabella, dove ogni riga corrisponde a un comando del test case e contiene nei suoi campi il nome dello stesso (command) e altri due parametri rappresentanti l'elemento target del comando e il suo valore (value). I comandi più comuni sono quelli di open, click e type, generati in automatico dal sistema (il cui fallimento decreta l'interruzione del test, e vengono anche chiamati azioni poichè manipolano lo stato dell'applicazione), mentre richiedono l'intervento del tester quelli di store (che invece lo 22 Stato dell'arte e valutazione di strumenti open source per il testing black box esaminano e lo memorizzano in variabili) e quelli di verify/assert. Questi ultimi sono in pratica le asserzioni (già viste in JUnit) che vengono utilizzate per verificare che lo stato dell'applicazione sia conforme a quanto ci si aspetta, con la sostanziale differenza che, se un assert fallisce il test è abortito, se è un verify a fallire, invece, il test continua la sua esecuzione, segnalando semplicemente l'errore verificatosi. Esiste un ulteriore tipo di asserzione, il waitFor, che in pratica attende che una determinata condizione diventi vera, ma se ciò non avviene in un pre-settato lasso di tempo (Timeout), il test viene inevitabilmente anche in questo caso arrestato. Una volta terminata la registrazione, il test case o l'intera test suite possono essere riprodotti sempre adoperando il tool, che riesegue i comandi inviati nel loro ordine, annotando nel log sottostante la tabella gli eventuali warnings o malfunzionamenti. Di seguito viene riportato un semplice esempio di utilizzo, ottenuto fotografando lo stato dello strumento alla fine della riproduzione di un test case sull'applicazione di ateneo, Campus, consistente nell'individuare l'orario di ricevimento del professor Tramontana Porfirio per il corso di "Ingegneria del Software II". Notiamo, inoltre, come i comandi definiti a mano dall'utente siano evidenziati in verde rispetto a quelli inseriti invece in automatico, e come sia stato generato il codice corrispondente in Selenese del test case. Figura 2.6 – Esempio di utilizzo di Selenium IDE – Vista Table 23 Stato dell'arte e valutazione di strumenti open source per il testing black box Figura 2.7 – Esempio di utilizzo di Selenium IDE – Vista Source Selenium IDE non è, però, caratterizzato solo da questa enorme semplicità d'impiego. Presenta anche un'altra caratteristica, citata già in precedenza, che risulta ad oggi essere fondamentale nella maggior parte dei suoi contesti d'utilizzo: viene, infatti, offerta l'ulteriore possibilità di esportare il test case generato in molti formati diversi, ed è innegabile che ciò abbia sicuramente favorito in questi anni la rapida diffusione e il successo dell'intera Selenium suite. 2.2.2 Selenium RC Con Selenium è, quindi, possibile generare ed eseguire test in un qualsiasi linguaggio di programmazione supportato dal tool: per farlo, prima dell'introduzione della versione 2.0, era necessario l'utilizzo esclusivo di un altro strumento della suite, ossia Selenium RC (Remote Control). Scritto in Java, questo componente è costituito da: una serie di librerie client (API) che rappresentano l'interfaccia tra i linguaggi di programmazione supportati (Java, C#, Ruby, PHP, etc.) e il server, consentendo la scrittura 24 Stato dell'arte e valutazione di strumenti open source per il testing black box di test in modo assolutamente flessibile; un server a linea di comando che permette di avviare un browser, cui vengono trasferiti i comandi utilizzando un altro componente della suite Selenium, ossia Selenium Core, basato su JavaScript. Questo significa che può essere efficacemente utilizzato sulla maggior parte dei browsers, dove vengono eseguiti, infine, i comandi specificati nel test case d'interesse. Questa straordinaria versatilità di Selenium semplifica, come è facile intuire, anche una sua eventuale integrazione con altri frameworks esistenti di unit testing, come ad esempio lo stesso JUnit di cui si è discusso in precedenza. Infatti, è sufficiente ad esempio esportare nel formato JUnit 4 il codice del test case generato da Selenium IDE ed inserirlo, con le opportune leggere modifiche e configurazioni, in un progetto creato ad esempio con Eclipse, a cui si dovrà aggiungere però, oltre alla libreria JUnit, la libreria Selenium client relativa agli script in codice Java. Il test diviene così un vero e proprio JUnit test, con la sola differenza che verrà eseguito, una volta avviato il server RC, tramite il browser così come in Selenium IDE, ma alla fine l'esito positivo o meno del test sarà comunque visualizzabile nell'ambiente Eclipse. 25 Stato dell'arte e valutazione di strumenti open source per il testing black box 2.2.3 Selenium WebDriver Dalla versione 2.0 di Selenium, è stato introdotto invece l'utilizzo di un altro strumento, Selenium WebDriver. Sviluppato per supportare al meglio la crescente dinamicità delle pagine web, WebDriver è basato su un meccanismo leggermente diverso da quello di Selenium RC, tramite "chiamate dirette" al browser. Le WebDriver API mantengono la flessibilità del framework, consentendo agli sviluppatori di creare i loro test in qualunque linguaggio supportato, ma i comandi (in Selenese oppure in uno dei suddetti linguaggi) sono stavolta inviati al browser tramite un browser-driver, una sorta di supporto nativo dello specifico browser all'automazione. Questo dimostra come WebDriver a differenza di Selenium RC, il cui funzionamento in fin dei conti non varia molto da caso a caso, risulta come realizzato "su misura" per ogni browser supportato, come Firefox, Internet Explorer, Opera e Chrome. E' questo browser-driver che invia i comandi al browser e ottiene da esso i risultati. In ogni caso, Selenium RC continua ad essere molto utilizzato, soprattutto nelle attività di manutenzione delle applicazioni. WebDriver inizia direttamente un'istanza del browser e la controlla. Non ha bisogno del server di Selenium per far partire i test, ma l'utilizzo di quest'ultimo potrebbe risultare necessario in alcuni casi, specialmente quando si cerca di eseguire i suddetti test su più macchine in remoto. Nelle ultime versioni di Selenium è stata, infatti, inclusa l'utilissima possibilità di supporto a WebDriver per i test di Selenium distribuiti, realizzati tramite l'ultimo importante componente della Selenium suite, e cioè Grid. 2.2.4 Selenium Grid Selenium Grid è un sistema automatico per la distribuzione trasparente di test su più server. E' basato sul coordinare l'operato di più server Selenium RC, così da permettere l'esecuzione in parallelo di tests su più piattaforme. Un server fa da hub centrale e controlla sulle macchine remote le varie istanze dei browsers, che possono anche essere di versioni o configurazioni differenti, senza che possano sorgere problemi di compatibilità. L'hub regola gli accessi alle suddette istanze, mantenendo una lista dei server che li forniscono e ricevendo tutte le richieste di tests che poi 26 Stato dell'arte e valutazione di strumenti open source per il testing black box distribuisce ai nodi giusti, fornendo feedback molto veloci da usare per migliorare l'applicazione. Figura 2.9 – Il funzionamento di Selenium Grid Si potrebbe anche pensare di utilizzare codice di test esistente e "distribuirlo"; purtroppo, però, non è fornita alcuna strategia di esecuzione parallela, perciò è consigliabile scrivere già i propri test in questa modalità. In ogni caso, l'indiscutibile vantaggio di questo approccio resta l'apprezzabile risparmio di tempo nel testing di una qualsiasi applicazione e inoltre la possibilità di avviare test sicuramente più ampi ed accurati rispetto all'utilizzo individuale. 2.3 Tobias Tobias è un tool per il testing combinatoriale che genera, a partire da un modello, un alto numero di test cases, così da migliorare il più possibile il livello di confidenza nel software che viene testato. Sviluppato dall'Università Joseph Fourier di Grenoble, il suo aspetto principale è sicuramente, come nei tools visti in precedenza, la sorprendente semplicità d'uso, resa ancora maggiore dal non necessitare di alcuna installazione, poichè lo si utilizza direttamente online, sul sito ufficiale [6]. 27 Stato dell'arte e valutazione di strumenti open source per il testing black box Figura 2.10 – Pagina iniziale del tool on-line Tobias L'originalità di Tobias risiede nel basarsi sulla sequenza di chiamate dei metodi del test case, anzichè semplicemente sulla combinazione dei valori dei loro parametri, e ciò permette di progettare test cases in termini del comportamento che si vuole che essi esercitino nel sistema piuttosto che sullo stato dello stesso, generando test molto più sistematici e che riescono a coprire anche situazioni che magari sarebbero state trascurate utilizzando un approccio manuale. In questo modo di sicuro aumentano considerevolmente le possibilità di rilevare gli errori del prodotto. Per poter usufruire dei benefici offerti da questo tool, basta caricare, tramite l'interfaccia piuttosto essenziale presentata sul sito e qui riportata, il file di testo contenente il modello su cui si vuole venga costruita l'intera test suite richiesta. Figura 2.11 – Schermata di upload di Tobias Questo file deve contenere come detto un modello che viene chiamato "test schema", ossia la definizione di vari set di operazioni "simili" e di valori rilevanti per ogni parametro, chiamati in Tobias "gruppi", e la cui sintassi di base è riportata di seguito: 28 Stato dell'arte e valutazione di strumenti open source per il testing black box group GroupName [ GroupQualifier = value , ...] { Sequence of instructions OR Set of instructions OR Set of values } Il file ha il limite di avere dimensione massima di 150 kB, ma questa non risulta essere una grossa preoccupazione, vista la forte compattezza presentata dai modelli di Tobias. Il test schema viene poi espanso in un set di sequenze dalle quali vengono computate tutte le combinazioni dei parametri di input per tutte le operazioni del pattern, producendo un gran numero di test cases che di sicuro porteranno alla rilevazione di un numero maggiore di errori rispetto al caso manuale. Ma la maggiore forza di Tobias risulta anche essere la sua debolezza. La dimensione della test suite può divenire un vero problema, a partire dalla dimensione massima del file di output (che viene inviato in un link via e-mail) di 4 MB che spesso tronca i risultati, ma anche in termini di risorse da utilizzare per generare ed eseguire il test. Per limitare questa "esplosione combinatoriale" è sempre meglio progettare il proprio modello di test con cura, evitando chiamate inutili e mantenendo al minimo il numero dei possibili valori dei parametri. In ogni caso la robustezza anche dell'output fornito rende più semplice la stessa manutenzione della test suite, garantendo nella maggior parte dei casi che le correzioni da effettuare siano minime. Tra i formati del file di output, poi, come si può notare, è disponibile quello di JUnit, garantendo quindi anche in questo caso la possibilità di un'integrazione semplificata con i propri test projects, facendo in modo che il collaudatore possa concentrarsi maggiormente sugli aspetti più rilevanti del testing. 2.4 Korat Korat è un ulteriore tool che può essere utilizzato per effettuare unit testing black box in modo combinatoriale, specialmente di implementazioni di strutture dati complesse, come ad esempio alberi binari, heap etc. . Scaricabile dal sito ufficiale insieme alle varie librerie addizionali che utilizza, la generazione di test automatica che Korat effettua è basata su forti vincoli strutturali (specificati da dei predicati Java, costruiti a partire dalle precondizioni del metodo da testare e che, 29 Stato dell'arte e valutazione di strumenti open source per il testing black box come delle asserzioni, devono essere soddisfatti dai casi di test) e su ulteriori limiti riguardanti le dimensioni degli input. Il metodo viene, quindi, eseguito su ogni caso di test e ne viene usato anche uno ulteriore di post-condizione che rappresenta un vero e proprio oracolo di test per verificare la correttezza dell'output. Grazie alla verifica del predicato, Korat genera i test cases in maniera efficace e rapida: vengono creati, infatti, in poco tempo, molti test cases, ma a struttura tutti differente tra loro (vengono detti non-isomorfici), e viene offerta anche la possibilità di visualizzare graficamente le strutture generate, come si può vedere dallo screenshot presentato di seguito in figura. Figura 2.12 – Utilizzo del tool Korat La sostanziale differenza che è possibile rilevare tra il funzionamento di Tobias e quello di Korat è che quest'ultimo (oltre al fatto di poter essere utilizzato efficacemente, come già detto, anche per strutture complesse) genera i diversi casi di test comprendendo in ognuno, oltre alla verifica delle precondizioni, la chiamata al singolo metodo della classe da testare, e utilizza un generatore che riesce a coprire un range considerevole di possibili input al sistema. Tobias, di contro, aggiunge invece la possibilità di esprimere un'intera sequenza di chiamate a metodi nel test schema di cui si è discusso, permettendo di raggiungere stati del sistema cui non sarebbe possibile arrivare così semplicemente in altro modo e di esprimere, inoltre, anche test sulla base del suo comportamento. 30 Stato dell'arte e valutazione di strumenti open source per il testing black box Conclusioni E' evidente che il provare la validità e la correttezza di un qualunque software non banale risulta essere sempre più articolato e faticoso di quanto ci si potesse immaginare, e si è ben compreso, quindi, il motivo che ha portato all'introduzione dei vari strumenti automatici attualmente disponibili, tramite i quali il collaudatore riesce sicuramente a ridurre molto lo sforzo e i costi di esecuzione del testing del prodotto. I tools esaminati (per i quali, per maggiori informazioni si rimanda alle documentazioni sui siti ufficiali, presenti alla fine della trattazione) si sono dimostrati, nel corso degli anni, dei validi supporti all'approccio black box del testing, con la loro semplicità di installazione e utilizzo, con le loro funzionalità essenziali e con le loro potenzialità, tutte caratteristiche che ne hanno favorito la rapida diffusione e il grande successo, e che probabilmente non hanno nulla da invidiare ai loro equivalenti commerciali, tanto che un loro miglioramento può essere pensato solo da un punto di vista che alla fine, in parte, qualcuno di essi è già riuscito a raggiungere: l'autogenerazione dei test cases più rilevanti e la riduzione del loro numero sulla base di informazioni contenute in specifiche anche formali, così da eliminare ad esempio casi di test inconcludenti o equivalenti tra loro, per generare test suites più efficienti e pertinenti a ciò che è il reale utilizzo del prodotto. Informazioni queste, che potrebbero essere prese ad esempio anche da pre- e post- condizioni, ipotesi sul valore assunto dai parametri o, addirittura, da diagrammi realizzati nelle fasi di progettazione dello stesso software. Si potrebbe anche pensare di affinare la selezione degli stessi valori di input da utilizzare, cosa che magari un ingegnere non riesce mai a fare manualmente senza tralasciare qualche caso utile o ridondarne qualcuno che magari tanto utile non è. Questi, come molti altri possibili miglioramenti, al di là della loro realizzabilità o meno, puntano tutti allo stesso obiettivo: semplificare e rafforzare un'attività che forse a volte non viene eseguita come si dovrebbe, ma dalla quale dipende l'intero ciclo di vita del prodotto e la soddisfazione di chi in futuro potrà e vorrà utilizzarlo. 31 Stato dell'arte e valutazione di strumenti open source per il testing black box Bibliografia [1] [I. Sommerville] [2007] “[Ingegneria del Software, 8a edizione]” [2] [R. Pressman] [2008] “[Principi di Ingegneria del Software, 5a edizione]” [3] [C. Ghezzi, M. Jazayeri, D. Mandrioli] [2004] “[Ingegneria del Software – Fondamenti e Principi, 2a edizione]” [4] [Documentazione JUnit] [http://junit.sourceforge.net/] [5] [Documentazione Selenium] [http://docs.seleniumhq.org/] [6] [Sito ufficiale Tobias] [http://tobias.liglab.fr] [7] [Documentazione Korat] [http://korat.sourceforge.net] [8] [Sito Campus] [http://www.campus.unina.it] 32