Ignorare condizionalmente i test in JUnit 4


365

OK, quindi l' @Ignoreannotazione è utile per contrassegnare che un caso di test non deve essere eseguito.

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 una macchina uniprocessore, non penso che sarebbe corretto semplicemente superare il test (dal momento che 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 giusto (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 dia questa flessibilità e sospetto che dovrò creare manualmente la suite di test per la classe in questione. Tuttavia, la documentazione non menziona nulla al riguardo e guardando attraverso l' API non è anche chiaro come questo sarebbe fatto a livello di codice (cioè come posso creare a livello di programmazione un'istanza Testo simile equivalente a quella creata @Ignoredall'annotazione?).

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

Risposte:


476

Il modo JUnit è farlo in fase di esecuzione org.junit.Assume.

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

Puoi farlo in un @Beforemetodo o nel test stesso, ma non in un @Aftermetodo. Se lo fai nel test stesso, il tuo @Beforemetodo verrà eseguito. Puoi anche farlo all'interno @BeforeClassper impedire l'inizializzazione della classe.

Un errore presupposto causa l'ignoramento del test.

Modifica: per confrontare con l' @RunIfannotazione di junit-ext , il loro codice di esempio sarebbe simile al seguente:

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

Per non parlare del fatto che è molto più semplice acquisire e utilizzare la connessione dal Database.connect()metodo in questo modo.


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

1
Per citare: "In futuro, questo potrebbe cambiare e un presupposto fallito potrebbe portare all'ignoramento del test." In effetti è cambiato, a partire dal 4.5 credo. L'attuale javadoc dice: "Il corridore JUnit predefinito tratta i test con ipotesi non riuscite come ignorati. I corridori personalizzati possono comportarsi in modo diverso." github.com/KentBeck/junit/blob/…
Yishai,

4
Eclipse 3.6 con Junit 4.8.1 riporta falsi presupposti come test di superamento. Lo stesso vale per la formica 1.8.1.
Fijiaaron,

8
Che Eclipse riporta ipotesi non riuscite poiché il passaggio è un bug: bugs.eclipse.org/bugs/show_bug.cgi?id=359944
Martin

1
@JeffStorey, allora stai cercando un paio di cose. Uno è l' @BeforeClassannotazione, in cui puoi far fallire il tuo presupposto, che salterà l'intera classe. Un altro è @ClassRule(per il controllo a grana fine, ma per l'intera classe, una volta).
Yishai,

51

Dovresti controllare il Junit-extprogetto. Hanno RunIfannotazioni che eseguono 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 tutorial]


3
Grazie per questa risposta: un'interessante sintassi alternativa per la funzionalità, anche se ci andrò Assumedirettamente per non introdurre un'altra dipendenza.
Andrzej Doyle,

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

Preferirei, perché questo aiuta a eseguire il test in modo condizionale in fase di esecuzione. Si adatta a dove verrà eseguito un numero di test unitari e il requisito è di eseguire i test unitari su un correttore specifico. Mi sono davvero sorpreso di vedere che junit-ext non è disponibile sul repository Maven. Come avremmo usufruito di questo nel progetto Maven.
Shambhu,

4
Un'annotazione come @RunIfsepara la condizione in cui un test dovrebbe essere eseguito dall'effettivo codice di test, che penso sia buono. Quello che non mi piace è che richiede un test runner particolare. Pertanto ho scritto una regola JUnit per ignorare in modo conditino i test.
Rüdiger Herrmann,

2
Dopo aver installato il vaso junit-ext (disponibile qui code.google.com/p/junit-ext/downloads/… ) nel nostro repository locale e aver implementato questa annotazione @RunIf ... niente! È totalmente ignorato e penso che la ragione potrebbe essere che junit-ext sembra dipendere da junit 4.5. Abbiamo bisogno di 4.9+ a causa del test di primavera. Quindi ... non importa.
Marc

7

In JUnit 4, un'altra opzione potrebbe essere quella di creare un'annotazione per indicare che il test deve soddisfare i tuoi criteri personalizzati, quindi estendere il runner predefinito con il tuo e usando la riflessione, basare la tua decisione sui criteri personalizzati. Potrebbe assomigliare a questo:

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 */
    }
}

Anche se questo sembra bello e pulito, non funziona con le versioni attuali se JUnit4, poiché BlockJUnit4ClassRunnernon offre più il isIgnoredmetodo.
Dave,

-2

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 allo stesso modo Assume.assumeTrue()ma non supera il test.


5
Come notato nelle risposte sopra, un'ipotesi fallita no passare il test, ma restituisce uno stato separato. Alcuni corridori potrebbero erroneamente riportarlo come se fosse un passaggio, ma si tratta di un punto debole / bug nel test runner (e il runner JUnit predefinito visualizza il test come ignorato). E per quanto riguarda la tua frase finale, fallire il test non è esattamente quello che voglio (ndr) fare.
Andrzej Doyle,

Oh va bene. I test hanno superato il presupposto fallito nel mio caso, ma volevo che fossero segnalati come falliti (stavo verificando un'eccezione da Test Watcher). Forzare un fallimento mi ha aiutato.
Nel
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.