2010-10-27 5 views
46

C'è un metodo fail() nella libreria JUnit4. Mi piace, ma ho riscontrato una mancanza del metodo pass() che non è presente nella libreria. Perché è così?JUnit4 fail() è qui, ma dove è pass()?

Ho scoperto che posso usare assertTrue(true), ma sembra ancora non logico.

@Test 
public void testSetterForeignWord(){ 
    try { 
    card.setForeignWord(""); 
    fail(); 
    } catch (IncorrectArgumentForSetter ex){ 
    } 

// assertTrue(true); 
} 
+7

Basta usare l'istruzione return - nella maggior parte dei casi che passerà come pass(). – topchef

+0

@topchef quel singolo commento colpisce il martello sulla testa, mentre tutti gli altri dibattono su quale sia accettabile e quale no. –

+0

Alcuni sistemi di test (perl Test :: Simple) hanno superato e fallito asserzioni. Junit, tuttavia, conta il numero di _test methods_ che passano e falliscono. Quindi Junit non ha lo stesso uso per un metodo 'pass'. –

risposta

51

Finché il test non un'eccezione, si passa, a meno che il @Test annotazione specifica un'eccezione prevista. Suppongo che uno pass() possa lanciare un'eccezione speciale che JUnit interpreta sempre come passante, in modo da cortocircuitare il test, ma che andrebbe contro il solito design dei test (vale a dire assumere successo e fallire solo se un'asserzione fallisce) e, se la gente avuto l'idea che fosse preferibile usare pass(), avrebbe rallentato in modo significativo una grande suite di test di passaggio (a causa del sovraccarico di creazione di eccezioni). I test falliti non dovrebbero essere la norma, quindi non è un grosso problema se hanno quel sovraccarico.

Nota che il vostro esempio potrebbe essere riscritto così:

@Test(expected=IncorrectArgumentForSetter.class) 
public void testSetterForeignWord("") throws Exception { 
    card.setForeignWord(""); 
} 

Inoltre, si dovrebbe favorire l'utilizzo di eccezioni Java standard. Il tuo IncorrectArgumentForSetter dovrebbe probabilmente essere un IllegalArgumentException.

+4

I metodi fail() e i metodi assertX() lanciano in realtà un AssertionError, che causa l'uscita impura del metodo di test. Ecco perché un risultato positivo indica il successo ... –

+0

-1 - il metodo pass() non sta facendo nulla, sta chiudendo il test immediatamente senza eccezioni. Sarebbe effettivamente equivalente all'istruzione return nella maggior parte dei casi (ad eccezione delle eccezioni previste, timeout, ecc.). – topchef

+1

@grigory: hai ragione che un metodo 'pass()' non può semplicemente non fare nulla, per evitare che un test fallisca dopo averlo chiamato. Quindi ho rimosso quella frase. – ColinD

2

Non è necessario il metodo pass perché, in assenza di AssertionFailedException dal codice di test, il caso di test dell'unità passerà.

Il metodo fail() in realtà lancia un'AssertionFailedException per fallire il testCase se il controllo arriva a quel punto.

+0

Penso che sia in realtà un junit.framework.AssertionFailedError. – Kyle

+0

E i casi di errore. dì iam ottenendo l'eccezione non visibile dal webdriver. Dovrei prendere l'eccezione e tornare. – sasikumar

50

Chiama return dichiarazione ogni volta che il test è terminato e superato.

+1

+1 deve essere la risposta corretta (nella maggior parte dei casi con eccezione di timeout attesi, ecc.) – topchef

3

Penso che questa domanda abbia bisogno di una risposta aggiornata, poiché la maggior parte delle risposte qui sono abbastanza obsolete.

primo luogo alla domanda del PO:

penso che la sua abbastanza ben accettato che l'introduzione del concetto di "excepetion previsto" in JUnit è stata una mossa sbagliata, dal momento che tale eccezione potrebbe essere sollevata da nessuna parte, e passerà il test. Funziona se si lanciano (e si asseriscono su) eccezioni molto specifiche del dominio, ma lancio solo quei tipi di eccezioni quando sto lavorando su un codice che deve essere assolutamente immacolato, - la maggior parte di APIS semplicemente lancia le eccezioni incorporate come IllegalArgumentException oppure IllegalStateException. Se due chiamate effettuate potrebbero potenzialmente lanciare queste eccezioni, l'annotazione @ExpectedException eseguirà il test di green-bar anche se è la riga sbagliata che genera l'eccezione!

Per questa situazione ho scritto una classe che sono sicuro che molti altri hanno scritto qui, questo è un metodo assertThrows:

public class Exceptions { 
    private Exceptions(){} 

    public static void assertThrows(Class<? extends Exception> expectedException, Runnable actionThatShouldThrow){ 
     try{ 
      actionThatShouldThrow.run(); 
      fail("expected action to throw " + expectedException.getSimpleName() + " but it did not."); 
     } 
     catch(Exception e){ 
      if (! expectedException.isInstance(e)) { 
       throw e; 
      } 
     } 
    } 
} 

questo metodo restituisce semplicemente se viene generata l'eccezione, che consente di fare ulteriori affermazioni/verifiche nel test.

con la sintassi java 8 il tuo test sembra davvero bello.Qui di seguito è uno dei test più semplici sul nostro modello che utilizza il metodo:

@Test 
public void when_input_lower_bound_is_greater_than_upper_bound_axis_should_throw_illegal_arg() { 
    //setup 
    AxisRange range = new AxisRange(0,100); 

    //act 
    Runnable act =() -> range.setLowerBound(200); 

    //assert 
    assertThrows(IllegalArgumentException.class, act); 
} 

questi test sono un po 'traballante, perché "l'atto" passo in realtà non esegue alcuna azione, ma penso che il significato è ancora abbastanza chiaro.

c'è anche una piccola libreria su Maven chiamata catch-exception che utilizza la sintassi stile mockito per verificare che le eccezioni vengano generate. Sembra carino, ma non sono un fan dei proxy dinamici. Detto questo, c'è sintassi è così liscia rimane allettante:

// given: an empty list 
List myList = new ArrayList(); 

// when: we try to get the first element of the list 
// then: catch the exception if any is thrown 
catchException(myList).get(1); 

// then: we expect an IndexOutOfBoundsException 
assert caughtException() instanceof IndexOutOfBoundsException; 

Infine, per la situazione che ho incontrato per arrivare a questa discussione, c'è un modo per ignorare test se qualche conidition è soddisfatta.

In questo momento sto lavorando per ottenere alcune DLL chiamate tramite una libreria java nativa di libreria-caricamento chiamata JNA, ma il nostro server di build è in ubuntu. Mi piace provare a guidare questo tipo di sviluppo con i test di JUnit - anche se a questo punto sono lontani dalle "unità "--. Quello che voglio fare è eseguire il test se sono su una macchina locale, ma ignoro il test se siamo su ubuntu. JUnit 4 ha una disposizione per questo, chiamato Assume:

@Test 
public void when_asking_JNA_to_load_a_dll() throws URISyntaxException { 
    //this line will cause the test to be branded as "ignored" when "isCircleCI" 
    //(the machine running ubuntu is running this test) is true. 
    Assume.assumeFalse(BootstrappingUtilities.isCircleCI()); 
    //an ignored test will typically result in some qualifier being put on the results, 
    //but will also not typically prevent a green-ton most platforms. 

    //setup 
    URL url = DLLTestFixture.class.getResource("USERDLL.dll"); 
    String path = url.toURI().getPath(); 
    path = path.substring(0, path.lastIndexOf("/")); 

    //act 
    NativeLibrary.addSearchPath("USERDLL", path); 
    Object dll = Native.loadLibrary("USERDLL", NativeCallbacks.EmptyInterface.class); 

    //assert 
    assertThat(dll).isNotNull(); 
} 
1

Penso che questa domanda è il risultato di un piccolo malinteso del processo di esecuzione del test. In JUnit (e in altri strumenti di test) i risultati vengono conteggiati per metodo, non per assert call. Non c'è un contatore, che tiene traccia di quanti passaggi/guasti sono stati eseguiti assertX.

JUnit esegue ciascun metodo di prova separatamente. Se il metodo restituisce correttamente, il test viene registrato come "passato". Se si verifica un'eccezione, il test viene registrato come "non riuscito". In quest'ultimo caso sono possibili due sottocasi: 1) un'eccezione di asserzione JUnit, 2) qualsiasi altro tipo di eccezione. Lo stato sarà "non riuscito" nel primo caso e "errore" nel secondo caso.

Nella classe Assert sono disponibili molti metodi abbreviati per l'esecuzione di eccezioni di asserzione. In altre parole, Assert è un livello di astrazione rispetto alle eccezioni di JUnit.

Ad esempio, questo è il codice sorgente di assertEquals su GitHub:

/** 
* Asserts that two Strings are equal. 
*/ 
static public void assertEquals(String message, String expected, String actual) { 
    if (expected == null && actual == null) { 
     return; 
    } 
    if (expected != null && expected.equals(actual)) { 
     return; 
    } 
    String cleanMessage = message == null ? "" : message; 
    throw new ComparisonFailure(cleanMessage, expected, actual); 
} 

Come si può vedere, in caso di parità non succede nulla, altrimenti un excepion saranno gettati.

Quindi:

assertEqual("Oh!", "Some string", "Another string!"); 

tiri semplicemente un'eccezione ComparisonFailure, che sarà catturato da JUnit, e

assertEqual("Oh?", "Same string", "Same string"); 

non fa nulla.

In sintesi, qualcosa come pass() non avrebbe alcun senso, perché non ha fatto nulla.

0

Stavo cercando il metodo pass per JUnit, in modo da poter cortocircuitare alcuni test che non erano applicabili in alcuni scenari (ci sono test di integrazione, piuttosto che test di unità pure). Quindi peccato che non ci sia.

Fortunatamente, c'è un modo per avere un test ignorato condizionale, che in realtà si adatta ancora meglio nel mio caso con assumeTrue metodo:

Assume.assumeTrue (isTestApplicable);

Quindi qui il test verrà eseguito solo se isTestApplicable è true, altrimenti il ​​test verrà ignorato.