MokaByte 92 - Gennaio 2005

Model Driven Testing nelle Applicazioni J2EE
Abbattere i tempi del test funzionale

di
Doriano Gallozzi
Model Driven Testing come estensione di MDA: sviluppo e test secondo modelli per parallelizzare entrambi i processi, uniformare i team di sviluppo e test e abbattere i tempi del test funzionale

Introduzione
Affrontare il test di un sistema software è uno stadio complesso ed estremamente critico, proprio perchè da esso dipende la messa in esercizio del sistema medesimo. E' di vitale importanza poter disporre di metodologie e strumenti il più efficienti possibile per mettere in opera il proprio ambiente di test, ma è necessario anche risolvere problemi di intercomunicabilità tra team di sviluppo e team di test, proprio in quanto spesso linguaggi, formalismi e tool impiegati sono profondamente diversi. La Model Driven Testing - la metodologia di test secondo la specifica UML 2.0 - si propone come mezzo per risolvere questo problema, integrando nel formalismo UML anche la possibilità di definire modelli di test, così da poter affrontare la problematica stessa del test già durante le fasi di sviluppo, anticipando i tempi e promuovendo una sensibile riduzione dei costi.
L'obiettivo del presente articolo è quello di descrivere tale metodologia, presentandone le caratteristiche e illustrandone, tramite un esempio concreto, alcune possibili utilizzazioni pratiche.

 

Il Processo di Test
Il Processo di Test rappresenta uno stadio fondamentale nell'ambito del Ciclo di Vita del Software proprio perchè è il momento, particolarmente critico, in cui si effettuano tutta una serie di verifiche necessarie a capire se l'applicazione sviluppata soddisfa quanto richiesto e quanto ci si aspetta, e se può quindi essere posta in esercizio o meno. Come specificato in rif.[1], il processo di test copre oltre il 50% dell'effort richiesto durante lo sviluppo di sistemi software. Nonostante ciò, il processo di test spesso è male integrato con le altre fasi dello sviluppo, e ciò è dovuto a diversi fattori, una delle quali è certamente il fatto che coloro che si occupano di sviluppo utilizzano formalismi, linguaggi, tool diversi da quelli utilizzati da chi si occupa del test, e questo fatto rende difficoltosa la comunicazione tra i diversi team così come l'interscambio di documentazione.
E' proprio con l'obiettivo di colmare questa lacuna e di fornire una metodologia utile per un approccio integrato tanto per lo sviluppo quanto per il test che nasce, nell'ambito della specifica UML 2.0, il cosiddetto U2TP, ossia l'UML 2.0 Testing Profile, una estensione del formalismo UML utile per poter identificare una serie di modelli di supporto al test, già durante le fasi dello sviluppo, al fine di rendere coerente tanto il modo di approcciare e comprendere lo sviluppo medesimo, quanto il processo di test, che proprio dagli elementi caratteristici dello sviluppo trae i propri.

 

Model Driven Architecture: progettare secondo modelli
La Model Driven Architecture (MDA nel seguito), descritta in rif.[2] e anche nei rif.[3], è una metodologia di sviluppo definita da Object Management Group. Essa è caratterizzata dalla possibilità di approcciare lo sviluppo di un sistema software complesso a partire da un modello di business completamente indipendente dalla tecnologia che verrà scelta per implementarlo.
Tale modello, denominato Platform Independent Model (PIM nel seguito) contiene tutti gli elementi che caratterizzano i soli aspetti di business - cioè privi di implicazioni tecnico-implementative - del sistema da sviluppare. A partire dal PIM, progettato servendosi del formalismo UML, viene poi tratto un insieme di modelli applicativi, ossia di stereotipi dipendenti dalle tecnologie scelte per implementare quel dato PIM: ad esempio, se stiamo sviluppando una applicazione J2EE 3-tier, dopo aver progettato il nostro PIM, dovremo da esso derivare un PSM per il Web, un PSM per la parte EJB, un PSM per la parte EIS. Da ciascuno di tali PSM verrà poi ricavato il codice (Java nel nostro caso) che costituirà la nostra applicazione.
Nella figura 1 una schematizzazione dei tre modelli secondo MDA.


Figura 1
- I tre Modelli caratteristici di MDA

Approcciare lo sviluppo di un sistema software utilizzando la metodologia MDA significa poter beneficiare dei differenti livelli di astrazione presenti nei vari stadi di sviluppo, modellando e dichiarando, piuttosto che implementando.
Corredando e integrando i diversi modelli MDA con i necessari processi di Analisi dei Requisiti (a monte) e Testing e Deployment (a valle), si ha la possibilità di "immergere" MDA nell'insieme dell'intero Ciclo di Vita dell'Applicazione, così come illustrato nella fig. 2.


Figura 2
- MDA nel Ciclo di Vita dell'Applicazione


Model Driven Testing: derivare il test dai modelli
Come spiegato in dettaglio in rif.[4], la Model Driven Architecture può essere utilizzata anche per la modellazione di test. La crescente complessità dei sistemi software odierni richiede la possibilità di integrare il processo di test ad un livello molto più alto rispetto a quanto si è abituati.
In tal modo, errori di progettazione e malfunzionamenti nell'implementazione possono essere individuati con considerevole anticipo già durante le fasi di sviluppo, permettendo di correggere il tiro con rapidità ed efficacia, e riducendo in tal modo i tempi di sviluppo e quindi i costi.
E' questa l'esigenza di base che porta a definire, all'interno della specifica UML 2.0, un profilo (ossia una particolarizzazione destinata ad un ben preciso obiettivo) dedicato al test, denominato appunto UML 2.0 Testing Profile, abbreviato come U2TP (rif.[5]). Esso, divenuto ufficialmente standard in ambito OMG a partire dal mese di Marzo 2004 (rif.[6]), colma la lacuna esistente tra sviluppatori e addetti al test, mettendo a disposizione un meccanismo basato su UML per poter definire e modellare le specifiche del test durante lo sviluppo di un sistema.
Riutilizzabilità, possibilità di astrarre e catturare le definizioni a un livello più alto, capacità di indirizzare il codice che esegue il test a partire da requisiti di business sono tutti aspetti presenti in U2TP, che in tal modo si presenta anche concettualmente come naturale estensione di MDA.
In pratica, U2TP offre la possibilità di definire le specifiche di test a partire dai modelli applicativi di un sistema.
Di qui la denominazione Model Driven Testing, e la sua stretta corrispondenza con MDA, essendone divenuto parte integrante e integrata (vedere figura 3).


Figura 3
- Model Driven Testing in ambito MDA

Come si può notare in figura, non appena è disponibile e sufficientemente stabile un modello di business (PIM), è possibile derivare da esso un modello di test indipendente dalla piattaforma (PIT), trasformabile in un modello applicativo (PST) ovvero direttamente in codice. Man mano che vengono eseguiti i diversi step di trasformazione, è possibile raffinare ulteriormente il test design model, arricchendolo di elementi quali il comportamento da seguire in caso di eccezioni inaspettate ovvero informazioni di controllo, configurazione e deployment.

 

U2TP: il profilo UML per il test in MDA
U2TP definisce una serie di concetti adatti ad affrontare la problematica del test secondo quanto definito dal cosiddetto approccio black-box (rif.[7]). In particolare, sono definiti quattro gruppi di concetti che riguardano quattro aree distinte, e cioè test architecture, test behavior, test data, e time. L'insieme di questi concetti definisce un linguaggio di modellazione completo e particolarmente adatto ad analizzare, specificare, visualizzare, costruire e documentare un sistema di test.
Qualche dettaglio su alcuni dei concetti U2TP per ciascuna area (si rimanda a rif.[4] per una trattazione completa):

Test architecture - uno o più oggetti vengono identificati come elementi componenti il cosiddetto System Under Test (SUT). Un insieme di test components viene allora predisposto all'interno del SUT per realizzare in pratica il comportamento oggetto del test, utilizzando il test context, che permette agli utenti di creare e raggruppare i test case, che vengono eseguiti dai test components sotto il controllo di uno scheduler.

Test behavior - basato sulla definizione di un obiettivo o test objective. Vengono quindi utilizzati alcuni particolari diagrammi UML (Interaction Diagrams e Activity Diagrams) per rappresentare osservazioni, invocazioni, azioni. Il tutto al fine di ottenere i verdicts, o risultati dei test, ad esempio pass o fail.

Test data - basati sulla definizione di elementi quali i data pool, insiemi significativi contenenti dati concreti, necessari per eseguire i test.

Time - concetti utilizzati per definire vincoli e controlli sui test basati sul tempo, ad esempio per accertarsi che determinati test terminino ovvero che un insieme di test venga eseguito nella medesima time zone.


Un esempio concreto
Un esempio potrà forse servire a illustrare meglio i concetti sin qui presentati. Per lo svolgimento dell'esempio qui presentato ci si è serviti dello strumento Compuware OptimalJ (rif.[8]), ambiente di sviluppo per applicazioni J2EE completamente conforme alla metodologia MDA, compresa l'estensione U2TP.
Partendo da una semplice applicazione J2EE, ci proponiamo di definire su di essa un Test Model e esaminare come esso si presenti, come sia strutturato e come possa essere utilizzato in pratica.

La nostra applicazione di partenza gestisce un semplice sistema CRM in cui vengono gestiti i dati di una serie di clienti (Customer) e le relative chiamate effettuate al sistema (Call), tenendo conto del Livello di Servizio con cui ciascun cliente è registrato nel sistema (ServiceAgreement).
In figura 4 il Class Diagram della applicazione in questione


Figura 4
- Class Diagram della Applicazione CRM

Modelliamo ora sul livello PSM Business Logic un componente di sessione destinato a restituirci, per un dato valore di Service Agreement, il numero di Customer che possiedono proprio quel valore specifico di ServiceAgreement.
A tal fine il nostro componente di sessione CustomersInfoBean.java possiederà un metodo di business che conterrà il seguente frammento di codice:

try{
  crm.application.business.logic.CustomerHome
customerHome;
  customerHome = (crm.application.business.logic.CustomerHome)
  serviceLocator.getRemoteHome("Customer",
                  crm.application.business.logic.CustomerHome.class);
  Collection foundCollection = customerHome.findByServiceAgreement(saId);
  int counter=0;
  Iterator iterator = foundCollection.iterator();
  while(iterator.hasNext()){
    counter++;
    iterator.next();
  }
  logger.debug("the value is " +counter);
  returnValue = counter;
  logger.debug("the returnValue is " +returnValue);
} catch (FinderException fe) {
  AlturaApplicationException aae = new AlturaApplicationException("yourKey");
} catch (RemoteException re) {
  AlturaRuntimeException are = new AlturaRuntimeException(re);
  throw are;
} catch (NamingException ne) {
  AlturaRuntimeException are = new AlturaRuntimeException(ne);
  throw are;
}

A partire da quanto presente nel PSM businesslogic, definiamo ora un Test Model.
Esso, denominato semplicemente testCRM, è costituito dal model package rosso nella figura 5. Come si può notare, esso contiene una serie di elementi relativi a quanto contenuto nel model package businesslogic, proprio perchè definito a partire da esso in modo da catturarne gli elementi oggetto del test.
Tra questi elementi, ne notiamo alcuni (sempre in fig.5) tra quelli citati come concetti caratteristici di U2TP, ad esempio i test components (CustomersInfoTest) o le test suite (crmEjbTestSuite), destinati a contenere i test case


Figura 5
- Definizione del Java Test Model

Il codice Java che viene generato a partire da questi elementi costituisce l'insieme del codice necessario a permetterci di eseguire i test. Nella figura 6 un dettaglio del codice generato a partire dal test component CustomerTest.


Figura 6
- Codice Java per eseguire i test

A questo punto si passa a definire i cosiddetti data pool, ossia insiemi di dati significativi necessari per eseguire i test. Nella figura 7 è presentato un esempio di definizione di data pool relativo al metodo di business customersInfo. L'interfaccia grafica messa a disposizione da OptimalJ permette di inserire facilmente il valore 0001 come identificativo di ServiceAgreement e il valore 3 come valore atteso per il numero di Customer. Ciò equivale a modellare l'assserzione " Quando l'operazione di conteggio dei Customer viene eseguita a fronte di un identificativo di ServiceAgreement pari a 0001, il numero restituito è 3", che equivale ad affermare che esistono 3 Customer che hanno un ServiceAgreement pari a 0001.


Figura 7
- Data Pool di Test


Creati i Data Pool per tutti gli altri test components, si tratta ora di "legare" insieme la suite di test (operazione Bind Test Suite). Il risultato di ciò sarà una suite di test pronta per essere eseguita e che, una volta lanciata, presenterà i diversi risultati ottenuti nella forma grafica di figura 8.


Figura 8
- Esecuzione della Suite di test

Si può notare come gli esiti (verdict) siano tutti positivi, e come non siano presenti nè errors, riferiti al codice Java che esegue i test, nè failures, ovvero test andati male. Se ad esempio si apre nuovamente il Data Pool già impostato per il test component CustomersInfo (fig. 6) e si inserisce il valore 4 al posto di 3, non si avranno errori sul codice che esegue i test, ma si avrà il fallimento di uno dei test, in quanto il risultato atteso 4 non coincide con quello ottenuto (che è sempre 3).
Questa è la situazione che si nota in figura 9.


Figura 9
- Nuova esecuzione della Suite di test


Estensione e generalizzazione dell'esempio visto
Quanto appena visto corrisponde ad un caso relativamente semplice di Data Driven Test, ossia di test definito e guidato da informazioni (dati) da verificare. Naturalmente, molti altri casi sono possibili e possono essere di interesse. Ad esempio, come definire un Test Model per quei metodi di business che non restituiscono dati (i metodi cosiddetti void)? Come è possibile utilizzare framework diffusi e apprezzati come Junit (rif.[9]) per il proprio Test Model? Come far valutare i risultati prodotti dal Test Model da una classe Java scritta da noi stessi (utilizzo di un custom evaluator)? A tutte queste tematiche, che mostrano ulteriori e più complessi impieghi di U2TP in ambito J2EE, è dedicata una sezione particolare appositamente sviluppata e reperibile in rif.[10].

 

Conclusioni
La Model Driven Architecture permette di approcciare lo sviluppo di un sistema complesso tramite la definizione e l'utilizzo di una serie di modelli. A completamento e integrazione di quanto offerto da essa, la Model Driven Testing permette utilizzare il formalismo UML anche per definire l'ambiente di test, catturando in appositi modelli (Test Model) i requisiti di business resi disponibili nei modelli di MDA. Questo fatto permette di ottenere un duplice obiettivo: uniformare il linguaggio di intercomunicazione esistente tra sviluppatori e addetti al test e mettere in opera l'ambiente di test durante le fasi stesse dello sviluppo, anticipando sensibilmente i tempi e garantendo una altrettanto sensibile riduzione dei costi.

 

Bibliografia
[1] Paul Baker, Zhen Ru Dai, Jens Grabowski, Øystein Haugen et al. "The UML 2.0 Testing Profile", Online copy su http://www.item.ntnu.no/fag/ttm4160/Artikler/U2TP-conquest.pdf
[2] Model Driven Architecture - http://www.omg.org/mda/
[3] Mokabyte - "Uso della Model Driven Architecture nello Sviluppo di Applicazioni J2EE", parte 1 http://www.mokabyte.it/2004/07/mda-1.htm e parte 2 http://www.mokabyte.it/2004/09/mda-2.htm)
[4] Zhen Ru Dai , "Model-Driven Testing with UML 2.0", Fraunhofer FOKUS, Kaiserin-Augusta-Allee 31, 10589 Berlin, Germany dai@fokus.fraunhofer.de
[5] U2TP Consortium "UML 2.0 Testing Profile" (2004) Final Adopted Specification
at OMG (ptc/04-04-02).
[6] UML Testing Profile su OMG, http://www.omg.org/technology/documents/modeling_spec_catalog.htm#UML_for_Testing
[7] B.Beizer, "Black-Box Testing", John Wiley & Sons, Inc (1995)
[8] Compuware Lab "OptimalJ Community" - http://javacentral.compuware.com
[9] JUnit - http://www.junit.org
[10] OptimalJ Testing Level Tutorials - http://javacentral.compuware.com/members/optimalj/documentation/v3.2.01/pe/pdf/Tutorials.pdf, cap. 1.7


Doriano Gallozzi è nato a Roma nel 1964 e si è laureato in Ingegneria Elettronica (indirizzo Informatica) nel 1989. Da sempre interessato a problematiche di analisi, progettazione e sviluppo di Sistemi Informativi, ha lavorato per diversi anni in aziende del settore informatico italiano (gruppo ENI, gruppo Telecom Italia), dove ha acquisito diverse esperienze tanto nel campo della progettazione e sviluppo del software (in ambiente M/F come in ambiente distribuito) quanto nel campo dei RDBMS (DBA su diversi progetti per clienti finali quali Telecom Italia). Da gennaio 2000 lavora nella Divisione Prevendita di Compuware Italia. La sua attività verte principalmente sulla piattaforma J2EE e tecnologie correlate, ma anche su ambiti tecnologici quali l'Enterprise Application Integration, i Portali Web, gli strumenti di Business Process Modeling.

MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it