2012-02-03 13 views
13

In un test di unità, ho bisogno di eseguire un setup abbastanza complesso (questo potrebbe essere un odore di codice ma questo non è quello di cui tratta questa domanda :-)) . Quello che mi interessa è se è meglio avere più metodi @Before che eseguono l'installazione o solo uno, che chiama i metodi di supporto per eseguire l'inizializzazione.Junit - Multiple @Before vs. one @Before divisi in metodi

E.g.

@Before 
public void setUpClientStub() { 

} 

@Before 
public void setUpObjectUnderTest() { 

} 

vs.

@Before 
public void setUp() { 
    setUpClientStub(); 
    setUpObjectUnderTest(); 
} 
+1

che dire di un baseclass? altrimenti non vedo alcun punto contro i metodi ... – wuppi

risposta

20

Come è stato detto in altre risposte, l'ordine in cui JUnit trova i metodi non è garantito, quindi l'ordine di esecuzione dei metodi @Before non può essere garantito. Lo stesso vale per @Rule, soffre della stessa mancanza di garanzia. Se questo sarà sempre lo stesso codice, non vi è alcun motivo di dividere in due metodi.

Se si dispone di due metodi, e, soprattutto, se si desidera utilizzarli da più luoghi, allora è possibile combinare regole utilizzando un RuleChain, che è stato introdotto a 4.10. In questo modo l'ordine specifico di regole, come ad esempio:

public static class UseRuleChain { 
    @Rule 
    public TestRule chain= RuleChain 
       .outerRule(new LoggingRule("outer rule")) 
       .around(new LoggingRule("middle rule")) 
       .around(new LoggingRule("inner rule")); 

    @Test 
    public void example() { 
     assertTrue(true); 
    } 
} 

Questo produce:

starting outer rule 
starting middle rule 
starting inner rule 
finished inner rule 
finished middle rule 
finished outer rule 

Così è possibile effettuare l'aggiornamento a 4.10 o semplicemente rubare la classe.

Nel tuo caso, puoi definire due regole, una per l'installazione del client e una per l'oggetto, e combinarle in un RuleChain. Utilizzando ExternalResource.

public static class UsesExternalResource { 
    private TestRule clientRule = new ExternalResource() { 
     @Override 
     protected void before() throws Throwable { 
     setupClientCode(); 
     }; 

     @Override 
     protected void after() { 
     tearDownClientCode() 
    }; 
    }; 

    @Rule public TestRule chain = RuleChain 
        .outerRule(clientRule) 
        .around(objectRule); 
} 

così avrete il seguente ordine di esecuzione:

clientRule.before() 
objectRule.before() 
the test 
objectRule.after() 
clientRule.after() 
+0

Questa è una bella soluzione, ma in termini di leggibilità avrei scelto il suggerimento di @hvgotcodes. – Timo

+1

Anche se i metodi non sono destinati ad essere riutilizzati, può avere senso averli come metodi separati per dare loro nomi significativi, invece di aggiungere commenti nel metodo. – herman

5

vorrei fare la seconda. AFAIK, non c'è modo di garantire l'ordine dei metodi di impostazione @Before annotati.

2

Non credo che faccia molta differenza, ma personalmente preferisco il secondo (l'ordine Prima che i metodi siano eseguiti non essendo definiti, avrete un controllo migliore in questo modo).

3

Si noti che non vi sono garanzie circa l'ordine con cui vengono richiamati i metodi annotati @Before. Se ci sono alcune dipendenze tra di loro (ad esempio, un metodo deve essere chiamato prima dell'altro), l'utente deve utilizzare l'ultimo modulo.

In caso contrario, è preferibile tenerli in un unico posto in modo che sia facile individuarli.

Problemi correlati