2010-04-14 22 views
124

Ho trovato l'uso corretto (o almeno la documentazione) di JUnit molto confuso. Questa domanda serve sia come riferimento futuro che come domanda reale.JUnit confusione: utilizzare 'estende TestCase' o '@Test'?

Se ho capito bene, ci sono due approcci principali per creare ed eseguire un test JUnit:

Approccio A (JUnit 3-style): creare una classe che estende TestCase, e iniziare a metodi di prova con la parola test. Quando si esegue la classe come test JUnit (in Eclipse), tutti i metodi che iniziano con la parola test vengono eseguiti automaticamente.

import junit.framework.TestCase; 

public class DummyTestA extends TestCase { 

    public void testSum() { 
     int a = 5; 
     int b = 10; 
     int result = a + b; 
     assertEquals(15, result); 
    } 
} 

Approach B (JUnit 4-style): creare una classe 'normale' e anteporre un @Test un'annotazione al metodo. Si noti che NON è necessario avviare il metodo con la parola test.

import org.junit.*; 
import static org.junit.Assert.*; 

public class DummyTestB { 

    @Test 
    public void Sum() { 
     int a = 5; 
     int b = 10; 
     int result = a + b; 
     assertEquals(15, result); 
    } 
} 

La miscelazione dei due sembra non essere una buona idea, si veda ad es. this stackoverflow question:

Ora, le mie domande (e) chiave:

  1. Qual è l'approccio preferito, o quando si usa uno invece dell'altro?
  2. L'approccio B consente di verificare le eccezioni estendendo l'annotazione @Test come in @Test(expected = ArithmeticException.class). Ma come si verificano le eccezioni quando si utilizza l'approccio A?
  3. Quando si utilizza metodo A, è possibile raggruppare un certo numero di classi di test in una suite di test in questo modo:

    TestSuite suite = new TestSuite("All tests");
    suite.addTestSuite(DummyTestA.class);
    suite.addTestSuite(DummyTestAbis.class);

    Ma questo non può essere utilizzata con metodo B (poiché ogni classe di test dovrebbe sottoclasse TestCase). Qual è il modo corretto per raggruppare i test per l'approccio B?

Edit: ho aggiunto le versioni JUnit per entrambi gli approcci

risposta

96

La distinzione è piuttosto facile:

  • estendere TestCase è la i test delle unità di modo sono stati scritti in JUnit 3 (ovviamente è ancora supportato in JUnit 4)
  • utilizzando l'annotazione @Test è la modalità introdotta da JUnit 4

In genere è necessario scegliere il percorso di annotazione, a meno che non sia necessaria la compatibilità con JUnit 3 (e/o una versione Java precedente a Java 5). Il nuovo modo ha diversi vantaggi:

Per eseguire il test per le eccezioni si attende in un JUnit 3 TestCase che avrebbe dovuto rendere il testo esplicito.

public void testMyException() { 
    try { 
    objectUnderTest.myMethod(EVIL_ARGUMENT); 
    fail("myMethod did not throw an Exception!"); 
    } catch (MyException e) { 
    // ok! 
    // check for properties of exception here, if desired 
    } 
} 
+0

Risposta utile e approfondita, ma non capisco completamente "controlla il messaggio di eccezione". Il controllo di una stringa hardcoded sarà un incubo di manutenzione. Devi aver inteso "controlla le proprietà del tuo specifico tipo di eccezione". – thSoft

+3

@thSoft: non è spesso usato, ma occasionalmente voglio assicurarmi che il metodo di eccezione menzioni il campo incriminato, per esempio. Quindi un semplice 'assertTrue (e.getMessage(). Contains (" foo "))' potrebbe essere utile. –

+1

Anche in JUnit4 questo è un idioma importante quando devi controllare il messaggio o qualche altra proprietà dell'eccezione (come la causa). Il metodo 'expected' controlla solo il tipo. – Yishai

21

ho una preferenza per JUnit 4 (approccio Annotazione) perché lo trovo più flessibile.

Se si vuole costruire suite di test in JUnit 4, è necessario creare una classe che raggruppa tutti i test come questo:

import org.junit.runner.RunWith; 
import org.junit.runners.Suite; 
import org.junit.runners.Suite.SuiteClasses; 


@RunWith(Suite.class) 
@SuiteClasses({ 
    Test1.class, 
    Test2.class, 
    Test3.class, 
    Test4.class 
})public class TestSuite 
{ 
/* empty class */ 
} 
1
  1. L'approccio "preferito" sarebbe quella di utilizzare le annotazioni che sono state introdotte dal Junit 4. Essi fanno un sacco di cose più facili (vedi la seconda domanda)

  2. È possibile utilizzare un semplice blocco try/catch per questo:


public void testForException() { 
    try { 
     Integer.parseInt("just a string"); 
     fail("Exception should have been thrown"); 
    } catch (final Exception e) { 
     // expected 
    } 
} 
3

si dovrebbe usare JUnit 4. E 'meglio.

Molti framework hanno iniziato a deprecare il supporto JUnit 3.8.

Questo è dalla Primavera documentazione di riferimento 3.0:

[Warning] Legacy JUnit 3.8 classe gerarchia è deprecato

In generale, si dovrebbe sempre cercare di utilizzare l'ultima versione stabile di una struttura quando inizi qualcosa di nuovo.

14

C'è una parte senza risposta alla tua domanda, e cioè "Qual è il modo corretto di raggruppare i test per l'approccio B?"

La risposta ufficiale è che si annota una classe con un @RunWith (Suite.classe) e quindi utilizzare l'annotazione @ Suite.SuiteClasses per elencare le classi. Questo è il modo in cui gli sviluppatori JUnit lo fanno (elencando manualmente ogni classe in una suite). In molti modi questo approccio è un miglioramento, in quanto è banale e intuitivo aggiungere prima i comportamenti di suite e after suite (basta aggiungere un metodo @BeforeClass e @AfterClass alla classe annotata con @RunWith - molto meglio del vecchio TestFixture).

Tuttavia, ha un passo indietro, in quanto le annotazioni non consentono di creare dinamicamente l'elenco di classi e aggirare il problema diventa un po 'brutto. Devi sottoclassi la classe Suite e creare dinamicamente l'array di classi nella sottoclasse e passarlo al costruttore Suite, ma questa è una soluzione incompleta in altre sottoclassi di Suite (come Categorie) che non funzionano con esso e in sostanza non supportano la raccolta di classi di test dinamiche.

+1

+1 per questo. Dopo aver intrapreso un'attività per scrivere una soluzione dinamica per aggiungere test a un TestSuite, ho dovuto estendere TestCase in ciascuno dei miei test. Questo a sua volta ha interrotto i test delle unità precedentemente funzionanti che utilizzavano le annotazioni JUnit4 per definire le eccezioni previste. La mia ricerca di un modo per popolare dinamicamente una Suite di test mi ha portato a questa discussione, e in particolare alla tua risposta, che credo sia uno dei pochi motivi desiderabili per continuare con JUnit 3. – 8bitjunkie