Login
Cerca all'interno di JavaPortal
Help
Home Page Documentazione Forum Progetti Partner Pubblica!
Documentazione > Tutorial > Tutorial JUnit
Modifica Impostazioni
Hide
Best Practices
EJB
Frameworks
Howto
J2EE
J2ME and Wireless
J2SE
JSP e Servlet
Java Application Server
Java IDE/Tools
Java Media
Java Security
Java Sys Admin
Java e XML
Java e SQL
OpenSource Java
Patterns
Repository
Tesi
UML
Web Services
Slide
White Paper di jws.it
project management
Eventi
Groovy

Hai una tesi in Java?
Tesine preparate
per esami?
Pubblica tutto su
JavaPortal!

Scrivi al nostro staff


5 trucchi da sapere sulle performance


Blaise Pascal
È molto più bello sapere qualcosa di tutto, che tutto di una cosa


Guida alle JSP – Lez 4: Gli oggetti impliciti


Rss Feed
Home Page
Articoli
News
Forum
Classi

  Visualizza Commenti (0) Aggiungi Commento    
Add to Shortcuts
 
Vota l'articolo
Tutorial JUnit
By Ettore Marcon
4 settembre 2005

  Tutorial JUnit
Program I problemi che si possono presentare in seguito sono:
Program Un processo più semplice
Program Automazione dei test con JUnit
Program Test layout
Program Installazione
Program Suggerimenti
Program Conclusioni

Il processo di test è alle basi dello sviluppo del software. Verificare il lavoro prodotto è una parte importante di ogni professione e questo vale anche per il programmatore. Quando il programmatore scrive una riga di codice è in grado di rilevare errori di digitazione durante la fase di compilazione. In seguito, è necessario eseguire dei test di corretto funziamento del sofware spesso manualmente.

Durante la modifica del codice per miglioramenti e aggiustamenti si possono introdurre dei bug, è necessario eseguire dei test su queste modifiche ma anche controllare che le modifiche non abbiamo cambiato il normale funzionamento del sofware.

Spesso si sente dire: "se compila allora funziona" questo ragionamento non si può applicare alla qualità del software. La qualità del sofware deve essere l'obiettivo di ogni progetto e deve essere pianificata fin dall'inizio in modo da coinvolgere tutte le fasi del ciclo di vita del software: dall'analisi fino all'ultima fase quella di mantenimento. Un progetto è di qualità se: rispetta le richieste del cliente, non ci sono bug di una certa gravità, ha un fault-rate basso e il costo di manutenzione si mantiene entro certi limiti prestabiliti. Il cliente stabilisce assieme ai progettisti del sofware dei requisiti e delle funzionalità che il progetto deve rispettare. Ci possono essere dei bug ma questi non devono mai compromettere il corretto funzionamento del software, è possibile classificare il bug in base alla sua gravità. Il software non deve bloccarsi e comunque la media dei blocchi di attività deve mantenersi bassa. Quando il sofware viene rilasciato il costo di manutenzione è inversamente proporzionale alla qualità del software prodotto, infatti se la progettazione e lo sviluppo sono stati correttamente pianificati e controllati la manutenzione si riduce a interventi sporadici.

Un modo per aumentare la qualità del sofware durante fase di sviluppo è quello di applicare dei test ad per ogni classe prodotta. Vediamo un esempio banale di una classe a cui è stato applicato un test:

Listato1:

package hello;

/**
* Classe di test, stampa "Hello World"
*
* @autor Ettore Marcon
* @version 0.2
*/
public class HelloWorld {

      /**
      * Restituisce "Hello World"
      *
      * @return La stringa "Hello World"
      */
      public String sayHello(){
      return "Hello World";

      }

      /**
      * Metodo main con il test della classe
      *
      * @param args Argomenti iniziali
      */
      public static void main(String[] args){
           HelloWorld world=new HelloWorld();
           System.out.println(world.sayHello());
      }
}// fine classe

Nel metodo main è stato inserito il test della classe usando il log (System.out.println) per verificare il valore resituito da sayHello().



I problemi che si possono presentare in seguito sono: top
  1. Disordine: al crescere della classe crescerà anche il metodo main(). La classe potrebbe diventare enorme a causa dei test.
  2. Codice e test in un unica classe: il codice prodotto è più grande a causa dei test. Non vogliamo rilasciare al cliente i test ma solo il prodotto.
  3. Test incerto: dal momento che il main() è parte della classe, main() ha accesso ai membri privati e ai metodi a cui gli altri sviluppatori non avranno accesso tramite l'interfaccia della classe. Per questo motivo, questa metodologia di testing conduce ad errori.
  4. Difficoltà nell'automatizzare i test: per rendere autonomi i test è necessario creare un secondo programma che passi gli argomenti al main().


Un processo più semplice top
La differenza rispetto al codice proposto prima è la separazione del codice di test dalla classe da controllare. La classe separata è chiamata anche unità di test. Questa tecnica fornisce diversi vantaggi:
  1. Un meccanismo per progettare la classe: perché sviluppo una classe attraverso la sua interfaccia. Ma dal momento che sviluppo la classe, ne conosco il funzionamento interno. In questo modo i test non sono una black box ma una white box dal momento che lo sviluppatore è responsabile di scrivere la classe e i test alla classe.
  2. Un esempio di utilizzo della classe: si separa l'esempio di utilizzo dall'implementazione. La separazione aiuta anche la tentazione dello sviluppatore di trarre vantaggio da caratteristiche interne alla classe che potrebbero non esserci in futuro.
  3. Senza main(): si evitano le limitazione riscontrate nell'utlizzo del main(), come ad esempio il passaggio di parametri multipli per la configurazione di differenti test. Si separano i test in tante classi, ognuna delle quali mantiene del codice individuale di inizializzazione. L'utilizzo di unità di test separate dal codice permette di fornire un modo di automatizzare il processo di validazione.
  4. Possiamo verificare che ogni nuovo cambiamento non abbia un effetto collaterale.
  5. Invece di aspettare di eseguire il test manualmente tramite l'interfaccia utente, possiamo controllare il codice prima di rilasciarlo. Questo aiuta a capire gli errori durante lo sviluppo abbasando il costo del codice di qualità.
  6. Nel fornire un processo incrementale di test, viene raggiunto un migliore processo di implementazione. Come il compilatore ci aiuta nel capire gli errori di sintassi, il processo incrementale di test ci aiuta nel capire gli errori durante le modifiche del codice.


Automazione dei test con JUnit top
Per poter automatizzare i test abbiamo bisogno di un framework. E' possibile svilupparne uno proprio, comperarne uno, oppure usare alcuni progetti open-source come JUnit. Usiamo JUnit per diverse ragioni:
  1. Non dobbiamo scrivere il nostro framework.
  2. E' un progetto open-source, così non è necessario acquistare un framework.
  3. Altri programmatori della comunità open-source lo usano, così è facile trovare esempi.
  4. Permette di separare i test dal codice.
  5. E' facile da integrare nel processo di compilazione.


Test layout top

Vediamo un esempio di una TestSuite in JUnit. Ogni test è composto da test case individuali.Ogni test case è una classe che estende TestClass e contiene ad esempio il codice di test che è stato usato nel main() nel listato 1.

Per convenzione la classe di test consiste dello stesso nome della classe da testare, ma con Test all'inizio (ad es. TestHelloWorld.java) e si trova all'interno dello stesso package della classe con l'aggiunta di test (ad es. se abbiamo hello.TestHelloWorld allora il package della classe di test sarà hello.test.TestHelloWorld). Il metodo sayHello() della classe HelloWorld deve essere modificato in modo da restituire la stringa "Hello World", il comportamento della classe rimane lo stesso perché all'interno del main() stampiamo il valore restituito da sayHello().

Listato 2:

/**
* Classe di test, stampa "Hello World"
*
* @autor Ettore Marcon
* @version 0.2
*/
class HelloWorld {

     /**
     * Restituisce "Hello World"
     *
     * @return La stringa "Hello World"
     */
     public String sayHello(){
           return "Hello World";

     }

    /**
    * Metodo main con il test della classe
    *
    * @param args Argomenti iniziali
    */
     public static void main(String[] args){
           HelloWorld world=new HelloWorld();
           System.out.println(world.sayHello());
     }
}// fine classe

La classe di test estende TestCase e al suo interno tutti i metodi di test inziano con testXXX. Il metodo testSayHello() confronta la stringa "Hello World" con quella che viene restituita dalla funzione sayHello() se non coincidono il test fallisce.

Listato 3:

package hello.test;

import hello.HelloWorld;
import junit.framework.TestCase;
import junit.framework.AssertionFailedError;

/**
* Classe di test JUnit contenente i test case per HelloWorld
*
* @autor Ettore Marcon
* @version 0.1
*/
public class TestHelloWorld extends TestCase{

       /**
       * Costruttore di default
       *
       * @param name Nome della classe
       */
       public TestHelloWorld(String name){
             super(name);

       }

      /**
      * Metodo main per il test della classe HelloWorld
      *
      *
      */
       public static void main(String[] args){
            junit.textui.TestRunner.run(TestHelloWorld.class);
       }

      /**
      * Test per il controllo del valore restituito dal metodo sayHello()
      */
       public void testSayHello(){
               HelloWorld world = new HelloWorld();
                assertEquals("Hello World",world.sayHello());
        }// fine test

}// fine classe

Supponiamo in fase di manutenzione di cambiare la classe HelloWorld e rendere "Hello World" una stringa statica. Durante la digitazione per errore possiamo scrivere "Hell0 World" al posto della 'o' scrivere uno '0'.

Listato 4:

package hello;

/**
* Classe di test, stampa "Hello World"
*
* @autor Ettore Marcon
* @version 0.3
*/
public class HelloWorld {

         private final static String HELLO_WORLD="Hell0 World";

          /**
          * Restituisce "Hello World"
          *
          * @return La stringa "Hello World"
          */
          public String sayHello(){
                   return HELLO_WORLD;

          }
}// fine classe

All'esecuzione di TestHelloWorld otteniamo questo messaggio d'errore:
.F
Time: 0,01
There was 1 failure:
1) testSayHello(hello.test.TestHelloWorld)junit.framework.AssertionFailedError:
expected:<Hello World> but was:<Hell0 World>
at hello.test.TestHelloWorld.testSayHello(TestHelloWorld.java:41)
at hello.test.TestHelloWorld.main(TestHelloWorld.java:31)

FAILURES!!!
Tests run: 1, Failures: 1, Errors: 0

Questo errore è difficile da scovare nel codice, ma se vengono creati dei test per ogni metodo o classe in seguito ad una modifica possiamo controllare se il comportamento della classe è ancora quello che ci si aspetta.

Vediamo adesso un esempio un po' più complesso, supponiamo di dover controllare il funzionamento di un metodo retriveQuestionMulti() della classe ForEachQuestion. Il metodo restituisce un hashtable con chiave e valore scomponendo due stringhe, la prima rappresenta le chiavi e la seconda i valori.

import java.util.*;


/**
* ForEach per processare le domande di una lista
*
* @author Ettore Marcon
* @version $Revision: 1.6 $
*/
        public class ForEachQuestion{

         /** class version */
               public static final String CLASS_VERSION =

"$Id: ForEachQuestion.java,v 1.6 2002/07/01 14:34:54 emarcon Exp $";

         /** separatore */
         public static final char CHAR_SEPARATOR=',';

       /**
       * Costruttore di default
       */
       public ForEachQuestion(){
       }

        /**
       * Gestione risposte multiple con ad es. question=1,3,5 e subQuestion=
       *
       * @param question Numero domanda
       * @param multi Numero di risposte multiple alla domanda
       * @return Ritorna un hashtable con chiave il numero di domanda e valore il numero totale di risposte
       */
         public Hashtable retriveQuestionMulti(String question, String multi){

        // controllo liste non vuote
         if (question==null || multi==null || question.length()==0 || multi.length()==0){
              return null;
          }// end if
        Hashtable list=new Hashtable();
        int i=0,iprec=0,j=0,jprec=0;
        // valori iniziali
        i=question.indexOf(CHAR_SEPARATOR,iprec);
        j=multi.indexOf(CHAR_SEPARATOR,jprec);
          while (i!=-1 && j!=-1){
                 list.put(question.substring(iprec,i++),multi.substring(jprec,j++));
                 iprec=i; jprec=j;
                 i=question.indexOf(CHAR_SEPARATOR,iprec);
                 j=multi.indexOf(CHAR_SEPARATOR,jprec);
         }// end if
        list.put(question.substring(iprec,(i!=-1)?i:question.length()),multi.substring(jprec,

(j!=-1)?j:multi.length()));
        return list;
}// end method


}// end class

Il metodo è molto più complesso da controllare rispetto alla classe SayHello, infatti in questo caso dobbiamo considerare diversi casi. La classe di test che è stata realizzata è la seguente:

import ForEachQuestion;
import java.util.*;
import junit.framework.*;
import junit.extensions.*;

/**
* JUnit testcases for ForEachQuestion
*
* @author Ettore Marcon
* @version $Id: TestForEachQuestion.java,v 1.2 2002/06/21 13:52:28 emarcon Exp $
*/
       public class TestForEachQuestion extends TestCase{

      /**
      * Costruttore di default
      */
      public TestForEachQuestion(String name) {
      super(name);
     }

      /**
      * Main, e' possibile il test diretto
      *
      * @param args[] Argomenti
      */
      public static void main(String args[]) {
      junit.textui.TestRunner.run(TestForEachQuestion.class);
      }

      // Classe oggetto di test
      private ForEachQuestion test;

     // Risultato dei test
     Hashtable result;

/**
* Imposta i dati necessari ad ogni test
*/
     public void setUp(){
             test=new ForEachQuestion();
              result=null;
    }

/**
* Rimuove i dati
*/
      public void tearDown(){
      test=null;
}

/**
* Lista question null multi null
*/
     public void testQuestionNullMultiNull(){
        result=test.retriveQuestionMulti(null,null);
        assertEquals("Hash ritornata dovrebbe essere null",null,result);
     }

/**
* Lista question null
*/
     public void testQuestionNull(){
              result=test.retriveQuestionMulti(null,"2");
              assertEquals("Hash ritornata dovrebbe essere null",null,result);
     }

/**
* Lista multi null
*/
     public void testMultiNull(){
              result=test.retriveQuestionMulti("2",null);
              assertEquals("Hash ritornata dovrebbe essere null",null,result);
      }

/**
* Lista question un valore ma niente multi
*/
      public void testQuestionOne(){
               result=test.retriveQuestionMulti("2","");
               assertEquals("Hash ritornata dovrebbe essere null",null,result);
      }

/**
* Lista niente question ma niente multi
*/
     public void testMultiOne(){
                result=test.retriveQuestionMulti("","2");
                assertEquals("Hash ritornata dovrebbe essere null",null,result);
     }

/**
* Lista question 1 e multi 2
*/
      public void testQuestion1Multi2(){
                 result=test.retriveQuestionMulti("1","2");
         assertEquals("Hash ritornata dovrebbe essere key 1 e value 2","2",(String)result.get("1"));
}

/**
* Lista question 1 e multi 2,3
*/
      public void testQuestion1Multi23(){
                  result=test.retriveQuestionMulti("1","2,3");
           assertEquals("Hash ritornata dovrebbe essere key 1 e value 2","2",(String)result.get("1"));
}

/**
* Lista question 1,3 e multi 2,3
*/
     public void testQuestion13Multi2(){
                 result=test.retriveQuestionMulti("1,3","2");
                 assertEquals("Hash ritornata dovrebbe essere key 1 e value 2","2",(String)result.get("1"));
     }

/**
* Lista question con virgola
*/
     public void testQuestionVirgolaMulti2(){
                result=test.retriveQuestionMulti(",","2");
                assertEquals("Hash ritornata dovrebbe essere key 1 e value 2","2",(String)result.get(""));
     }

}// end class

I test proposti sono abbastanza chiari grazie all'uso di commenti all'interno delle condizioni di assert. Nei test è importante considerare tutte le varie possibilità. I casi particolari sono quelli da valutare attentamente.

Se durante lo sviluppo o dopo il rilascio si dovesse trovare un bug all'interno della classe si dovrà costruire un unit test che simuli il bug e la classe verrà nuovamente rilasciata solo se supererà tutti i test della suite.



Installazione top

Nel sito www.junit.org è possibile fare il download delle librerie Junit e la documentazione. Si tratta di scaricare il file junit.zip e scompattarlo all'interno di una directory del vostro harddisk. E' necessario aggiungere al vostro classpath junit.jar, ad esempio: classpath=%classpath%;INSTALL_DIR\junitX.X\junit.jar

Nella classe di test si deve importare:
import junit.framework.*;

ed estendere TestCase:
public class TestHelloWorld extends TestCase{
}

I test devono iniziare con testXXX:
public testDoThisFirst(){
}

Se all'interno del metodo vengono lanciate delle eccezioni nel caso di assert che falliscono verrà indicato un failure altrimenti un errore.

I vari tipi di assert dispongono tutti di un parametro opzionale per impostare un messaggio di warning. Gli assert disponibili sono:

assertEquals(double expected, double actual) // confronta due numeri double
assertEquals(long expected, long actual) // confronta due numeri interi
assertNotNull(Object obj) // controlla che l'oggetto non sia nullo
assertNull(Object obj) // controlla che l'oggetto sia nullo
assertSame(Object expected, Object actual) // expected == actual, confronto per riferimento
fail() // lancia un'eccezione al test
fail(String messaggio) // lancia un'eccezione al test con un messaggio di warning

Se è necessario impostare dei dati iniziali e rilascirali ad ogni test usare rispettivamente i metodi setUp() e tearDown(), ad esempio:

public class FixtureDemo extends TestCase{
private FileReader demoReader;

public void setUp() throws IOException{
        demoReader=new FileReader("demo.dat");
}

public void tearDown() throws IOException{
        demoReader.close();
}

Sono disponibili per i test i seguenti metodi run:
se abbiamo impostato all'interno del main(), junit.textui.TestRunner.run(TestHelloWorld.class) basterà eseguire da riga di comando: java TestHelloWorld, oppure java junit.textui.TestRunner TestHelloWorld

Se vogliamo utilizzare una GUI di test:
java junit.swingui.TestRunner TestHelloWorld java junit.swingui.LoadingTestRunner TestHelloWorld nell'ultimo caso oltre ad avere una gui per i test ad ogni esecuzione verrà ricaricata la classe o le classi, non funziona con file .jar.

E' possibile stabilire quali metodi di test eseguire all'interno di una suite, ad esempio:
public static Test suite(){
     TestSuite suite=new TestSuite();
      suite.addTest(new TestHelloWorld("testSample1"));
      suite.addTest(new TestHelloWorld("testSample2"));
      suite.addTest(new TestHelloWorld("testSample3"));
      return suite;
}

e usare il metodo main(...) in questo modo per i batch test:
public static void main(String[] args){
        junit.textui.TestRunner.run(suite());
}

 



Suggerimenti top

1.Non usare il costruttore della classe test case per impostare i valori di default nei test.

Impostare i dati di default all'interno del costruttore non è corretto perché possiamo ottenere un'eccezione IllegalStateException. Junit in risposta all'eccezione lancerà un AssertionFailedError, indicando che il test non può essere instanziato. Dalla lettura dello stack trace non si riconosce se il problema è legato al test oppure all'impostazione dei dati di default nel costruttore della classe.

Il metodo corretto per impostare i dati di default è l'ovverriding del metodo setUp(). Ogni eccezione lanciata all'interno di setUp() viene riportata correttamente.

public void setUp(){
// inizializzazione dei dati di default
}

Il metodo setUp() viene eseguito prima di ogni test ed è da preferire rispetto ad impostazioni generali nel costruttore o nei metodi di test.


2.Non assumere alcun ordine nell'esecuzione dei test.

Junit usa reflection per individuare i test da eseguire pertanto non è possibile conoscere a priori l'ordine di esecuzione dei test. L'esecuzione dei test in differenti piattaforme e Java VM può produrre differenti risultati se i test non sono indipendenti tra loro ed eseguibili in qualsiasi ordine.

Nei casi in cui sia importante l'ordine d'esecuzione dei test è possibile usare una test suite. Il metodo suite permette di definire un Vector di test, ad esempio:

public static Test suite(){
    suite.addTest(new SomeTestCase("testDoThisFirst"));
    suite.addTest(new SomeTestCase("testDoThisFirst"));
}
Nell'API di Junit non c'è alcuna garanzia che l'ordine dei test sarà quella indicata ma nella suite viene impiegato un Vector per memorizzare i test. Pertanto ci possiamo aspettare che i test saranno eseguiti nell'ordine con cui sono stati aggiunti al vettore come proposto nell'esempio.

3.Evitare side effect nello scrivere i test.

I test che abbiano side effect hanno due problemi:
  1. possono cambiare i dati degli altri test.
  2. non è possibile ripetere i test senza un intervento umano.


Nella prima situazione i test possono essere eseguiti correttamente da soli. Comunque se incorporati all'interno di un test suite possono condurre altri test a fallire. E' in seguito difficile capire perché il test è fallito, anche perché l'errore si può trovare lontano dal test con side effect.

Nella seconda situazione, un test può aggiornare lo stato del sistema e pertanto non può essere eseguito ancora senza un intervento manuale che può consiste nel cancellare i dati del test dal database. Per questo genere di test si pongono due problemi, primo deve essere documentato l'intervento necessario all'esecuzione del test e secondo non è più possibile eseguire i test automaticamente.

4.Chiamare i metodi della superclasse setUp() e tearDown() quando si estende una classe di test.

Attenzione ad estendere assieme alla classe di test anche i metodi setUp() e tearDown().

public class SomeTestCase extends AnotherTestCase{

      public SomeTestCase(String testName){
             super(testName);
}

public void setUp(){
super.setUp();
// aggiungiamo i dati da inizializzare
}

public void tearDown(){
     super.tearDown();
     // aggiungiamo i dati da rilasciare
     }
}// fine classe di test

5.Non usare riferimenti a locazioni del filesystem direttamente nel codice.

Un test spesso deve leggere dei dati dal un file all'interno del file system. Consideriamo il seguente caso:

public void setUp(){
        FileInputStream in("c:\\testdata\\test.txt");
     ...
}

Il codice utilizza un file che si trova nel path c:\testdata. L'assunzione non è corretta in due situazioni:
-potrei aver bisogno di utilizzare un disco diverso da c:\.
-il test potrebbe avere luogo in un altro sistema operativo diverso da Windows come ad esempio Unix.

Una soluzione può essere:

public void setUp(){
      FileInputStream in("test.txt");
     ...
}

La soluzione è valida solo se il test viene eseguito nella stessa directory in cui si trova il file di test. In alcune situazioni è difficile integrare diversi test in una suite senza continuamente cambiare la directory corrente. Per risolvere il problema si può usare Class.getResource() oppure Class.getResourceAsStream(), significa caricare resource da una directory relativa al classpath di origine.

6.Mantenere i test assieme alle classi sotto test.

Se i test sono mantenuti assieme alle classi sotto test, sia i test che le classi saranno compilate durante la fase di build. Questo forza il programmatore a mantenere i test e le classi sincornizzate durante lo sviluppo e a considerare i test parte del normale sviluppo del software.

7.I nomi dei metodi dei test devono essere significativi.

Se dobbiamo eseguire i test della classe MessageLog, il nome della classe di test dovrebbe essere TestMessageLog. Il nome dei metodi di test dovrebbero descrivere i test, in questo modo:
testLoggingEmptyMessage()
testLoggingNullMessage()
testLoggingWarningMessage()
testLoggingErrorMessage()

Il nome del metodo è importante per capire lo scopo del test senza dover leggere la documentazione.

8.Assicurare che il test sia indipendente dal tempo di esecuzione.

Quando possibile evitare di usare dati che possono scadere, i dati non più disponibili dovrebbero essere inseriti manualmente oppure aggiornati automaticamente. Il test dovrebbe essere indipendente dal tempo senza la necessità di aggiornare i dati.

9.Considerare i locale quando si scrivono i test.

Quando si usano date o classi dipendenti dalla localizzazione fare attenzione a che il codice di test ne sia indipendente, ad esempio:

Date date=DateFromat.getInstance().parse("dd/mm/yyyy");

Se usiamo un computer con un diffente locale, il codice scritto sopra non funziona. Per evitare questi problemi è meglio scrivere:

Calendar cal=Calendar.getInstance();
cal.set(yyyy,mm-1,dd);
Date date=Calendar.getTime();

10.Utilizzare i metodi assert/fail di Junit e exception handling per avere codice di test più pulito.

Esempio:

public void testExample(){
      try{
          // esegue la classe da testare
          }catch(SomeApplicationException e){
              fail("Exception");
          }
}// fine test

Junit automaticamente intercetta le eccezioni. Se vengono considerate le eccezioni degli errori, significa che l'esempio sopra contiene del codice rindondante e dovrebbe essere modificato in questo modo:

public void testExample() throws SomeApplicationException{
       // esegue la classe da testare
}// fine test

Inoltre invece di scrivere:
assertTrue(result=3);

è preferibile scrivere:
assertEquals("Il risultato della funzione dovrebbe essere 3",result,3);

Il codice scritto sopra è più utile di una semplice assert perché è di facile lettura e se l'asserzione fallisce fornisce più informazioni ad un tester.

E' possibile confrontare anche numeri decimali (floating point) in base ad un intervallo (delta):
assertEquals("un messaggio",result, expected,delta);

L'ambito in cui si usano le assertSame() e assertEquals() è il seguente:
   1. assertSame(): confornta due riferimenti che puntano allo stesso oggetto.
   2. assertEquals(): confronta due oggetti che sono uguali.

11.Documentare i test in javadoc.

La soluzione migliore per documentare i test da eseguire su di una classe è quello di scrivere i commenti direttamente nel codice con la notazione javadoc.

12.Evitare il controllo umano.

L'uso dei test serve ad automatizzare il controllo delle classi e del loro funzionamento, in alcuni casi è difficile evitare il controllo umano dell'output da una classe perché si tratta di oggetti complessi. Il caso più interessante per noi sono le servlet, ci sono diversi metodi per testare le servlet senza dover usare il controllo umano. Ad esempio, è possibile scrivere un dummy servlet framework e preconfigurarlo per i test. Un framework deve contenere le classi derivate da un normale ambiente di servlet. Le derivazioni hanno lo scopo di preconfigurare la loro risposta alle chiamate dei metodi.

HttpServletRequest: può essere estesa per permettere al test di specificare l'header, method, path info e altri dati.
HttpServletResponse: può essere estesa in modo da ottenere in output un stream che memorizzi la risposta della servlet in una string per il test.

Una soluzione più semplice è usare HttpUnit e Cactus in combinazione con i MockObjects in modo da simulare l'ambiente in cui la servlet lavorerà.

13.Mantenere i test piccoli e veloci:

Eseguire ogni test per tutto il sistema non dovrebbe richiedere delle ore. Perciò lo sviluppatore eseguire i test che siano veloci. Senza eseguire regolarmente tutti i test è difficile validare l'intero sistema quando siano state eseguite delle modifiche.



Conclusioni top
Il framework Junit permette di automatizzare i test durante la fase di sviluppo e di manutenzione. L'uso di Junit nello sviluppo di sofware open source ha reso possibile la distribuzione di sorgente con un numero ridotto di bug. I programmatori open source sono in grado di rilasciare del codice testato e verificato grazie a Junit. Credo che ogni programmatore dovrebbe usare sistematicamente Junit per poter rilasciare del codice di qualità, verificato e controllato.
 
Risorse:
http://www.dimi.uniud.it/~baruzzo/repository/sqa/sqa.htm
http://www.junit.org
http://www.javaworld.com/jw-12-2000/jw-1221-junit.html
http://junit.sourceforge.net/


Username:
Password:
To sign up for an account, click register... Register
Hide





Powered By



Campagna Anti-IF


Skin


PARTNER
Zio Budda
HostingJava


LICENZA



Eccetto dove diversamente specificato, i contenuti di questo sito sono rilasciati sotto licenza Creative Commons

Sitemap  © 2002-2004 Copyright Information. Privacy . Today is domenica 1 agosto 2010