2009-11-06 8 views
258

OK, quindi l'annotazione @Ignore è utile per contrassegnare che un test case non deve essere eseguito.Test ignorando in modo condizionale in JUnit 4

Tuttavia, a volte voglio ignorare un test basato sulle informazioni di runtime. Un esempio potrebbe essere se ho un test di concorrenza che deve essere eseguito su una macchina con un certo numero di core. Se questo test fosse eseguito su un computer uniprocessore, non penso che sarebbe corretto passare semplicemente il test (poiché non è stato eseguito), e certamente non sarebbe giusto fallire il test e rompere la build .

Quindi voglio essere in grado di ignorare i test in fase di esecuzione, poiché questo sembra il risultato corretto (poiché il framework di test consentirà il passaggio della build ma registrerà che i test non sono stati eseguiti). Sono abbastanza sicuro che l'annotazione non mi darà questa flessibilità e sospetto che avrò bisogno di creare manualmente la suite di test per la classe in questione. Tuttavia, la documentazione non menziona nulla a riguardo e guardando attraverso lo API non è nemmeno chiaro come ciò sarebbe fatto a livello di programmazione (cioè come faccio a creare in modo programmatico un'istanza di Test o simile che è equivalente a quella creata dall'annotazione @Ignore?).

Se qualcuno ha fatto qualcosa di simile in passato, o ha una brillante idea di come potrei fare altrimenti, sarei felice di sentirne parlare.

risposta

347

La JUnit è quello di fare questo in fase di esecuzione è org.junit.Assume.

@Before 
public void beforeMethod() { 
    org.junit.Assume.assumeTrue(someCondition()); 
    // rest of setup. 
} 

Lo si può fare in un metodo @Before o nella prova di sé, ma non in un metodo @After. Se lo fai nel test stesso, il tuo metodo @Before verrà eseguito. Puoi anche farlo entro @BeforeClass per impedire l'inizializzazione della classe.

Un errore di presupposto fa ignorare il test.

Edit: da confrontare con il @RunIf annotazione dal JUnit-ext, il loro codice di esempio sarebbe simile a questa:

@Test 
public void calculateTotalSalary() { 
    assumeThat(Database.connect(), is(notNull())); 
    //test code below. 
} 

Senza contare che è molto più facile da catturare e utilizzare la connessione dal metodo Database.connect() in questo modo.

+1

@notnoop, questa non è affatto la mia osservazione. Sono ignorati. Il test runner IDEA li segnala in questo modo, e uno sguardo al codice sorgente JUnit mostra che segnala il test come ignorato. – Yishai

+1

Per citare: "In futuro, questo potrebbe cambiare, e un'assunzione fallita potrebbe portare a ignorare il test." In effetti è cambiato, a partire da 4.5 credo. L'attuale javadoc dice: "Il runner JUnit predefinito tratta i test con ipotesi errate come ignorate.I corridori personalizzati possono comportarsi diversamente." http://github.com/KentBeck/junit/blob/7aac4b19d359285041ccb51d575235339a1a8be0/src/main/java/org/junit/Assume.java – Yishai

+0

Grazie, è esattamente quello che sto cercando. La semantica di "Assume" sembra esattamente quello che sto cercando di fare qui, quindi anche se un corridore non lo tratta come "@ Ignore", credo che verrà gestito in modo appropriato. –

37

Si consiglia di verificare il progetto Junit-ext. Hanno RunIf annotazione che esegue i test condizionali, come:

@Test 
@RunIf(DatabaseIsConnected.class) 
public void calculateTotalSalary() { 
    //your code there 
} 

class DatabaseIsConnected implements Checker { 
    public boolean satisify() { 
     return Database.connect() != null; 
    } 
} 

[Esempio di codice tratto dal loro esercitazione] modo

+3

Grazie per questa risposta - una sintassi alternativa interessante per la funzionalità, anche se io vado con 'Assume' direttamente in modo da non introdurre un'altra dipendenza. –

+2

Personalmente preferisco questa soluzione. Se hai molti test che dovrebbero essere eseguiti in base alle stesse condizioni, questo sarebbe molto più ideale di dover usare Assume in ogni test. Inoltre, se questo può essere usato a livello di classe piuttosto che a livello di metodo, sarà ancora più ideale. – Richard

+3

junit-ext non è disponibile su Maven Central :-( –

-1

Una breve nota: Assume.assumeTrue(condition) ignora il resto dei passaggi ma supera il test. Per fallire il test, utilizzare org.junit.Assert.fail() all'interno dell'istruzione condizionale. Funziona come Assume.assumeTrue() ma fallisce il test.

+2

Come indicato nelle risposte precedenti, un'ipotesi fallita fa ** non ** perché il test passi, restituisce uno stato separato. Alcuni runner potrebbero erroneamente riportare questo * come se * fosse un passaggio, ma questo è un punto debole/bug nel runner di test (e il runner JUnit predefinito visualizza il test come ignorato). E per quanto riguarda la tua frase finale, fallire il test non è specificamente ciò che voglio (ed) fare. –

+0

Oh OK. Nel mio caso i test hanno superato l'ipotesi fallita, ma volevo che venissero segnalati come non riusciti (stavo controllando un'eccezione da Test Watcher). Costringere un fallimento mi ha aiutato. –

4

In JUnit 4, un'altra opzione potrebbe essere quella di creare un'annotazione per indicare che il test deve soddisfare i criteri personalizzati, quindi estendere il runner predefinito con il proprio e utilizzando la riflessione, basare la propria decisione sui criteri personalizzati.Può sembrare qualcosa di simile:

public class CustomRunner extends BlockJUnit4ClassRunner { 
    public CTRunner(Class<?> klass) throws initializationError { 
     super(klass); 
    } 

    @Override 
    protected boolean isIgnored(FrameworkMethod child) { 
     if(shouldIgnore()) { 
      return true; 
     } 
     return super.isIgnored(child); 
    } 

    private boolean shouldIgnore(class) { 
     /* some custom criteria */ 
    } 
}