JUnit 5: come affermare che viene generata un'eccezione?


215

Esiste un modo migliore per affermare che un metodo genera un'eccezione in JUnit 5?

Attualmente, devo utilizzare una @Rule per verificare che il mio test generi un'eccezione, ma questo non funziona nei casi in cui mi aspetto che più metodi generino eccezioni nel mio test.


1
potresti essere interessato a controllare AssertJ per verificare le eccezioni in quanto è più flessibile di JUnit5
user1075613

Risposte:


325

È possibile utilizzare assertThrows(), che consente di testare più eccezioni all'interno dello stesso test. Con il supporto per lambdas in Java 8, questo è il modo canonico per testare le eccezioni in JUnit.

Secondo i documenti di JUnit :

import static org.junit.jupiter.api.Assertions.assertThrows;

@Test
void exceptionTesting() {
    MyException thrown = assertThrows(
           MyException.class,
           () -> myObject.doThing(),
           "Expected doThing() to throw, but it didn't"
    );

    assertTrue(thrown.getMessage().contains("Stuff"));
}

11
Da una vecchia scuola "Non so molto su Junit5 e probabilmente non abbastanza su Java8" ... sembra piuttosto bizzarro. Ti dispiacerebbe aggiungere qualche spiegazione in più; come "in quale parte c'è il vero" codice di produzione "sotto test ... che dovrebbe essere lanciato"?
GhostCat,

1
() -> punta a un'espressione lambda che accetta zero argomenti. Pertanto, il "codice di produzione" che dovrebbe generare l'eccezione si trova nel blocco di codice indicato (ovvero, l' throw new...istruzione tra parentesi graffe).
Sam Brannen,

1
Tipicamente l'espressione lambda interagisce con il soggetto in esame (SUT). In altre parole, lanciare direttamente un'eccezione come sopra è solo a scopo dimostrativo.
Sam Brannen,

1
Sembra che prevedono che i passi siano deprecati. I documenti dicono di usare assertThrows () invece ora.
deypypher

5
A partire dalla versione 5.0.0-M4 awaThrows non è più disponibile. È consentito solo assertThrows . Vedi github.com/junit-team/junit5/blob/master/documentation/src/docs/… : 'Metodo Assertions.expectThrows obsoleto rimosso a favore di Assertions.assertThrows ()'
gil.fernandes,

91

In Java 8 e JUnit 5 (Jupiter) possiamo affermare eccezioni come segue. utilizzandoorg.junit.jupiter.api.Assertions.assertThrows

public static <T extends Throwable> T assertThrows (Class <T> expectedType, eseguibile eseguibile)

Asserisce che l'esecuzione dell'eseguibile fornito genera un'eccezione del tipo previsto e restituisce l'eccezione.

Se non viene generata alcuna eccezione o se viene generata un'eccezione di un tipo diverso, questo metodo non riuscirà.

Se non si desidera eseguire ulteriori controlli sull'istanza dell'eccezione, ignorare semplicemente il valore restituito.

@Test
public void itShouldThrowNullPointerExceptionWhenBlahBlah() {
    assertThrows(NullPointerException.class,
            ()->{
            //do whatever you want to do here
            //ex : objectName.thisMethodShoulThrowNullPointerExceptionForNullParameter(null);
            });
}

Tale approccio utilizzerà l'interfaccia funzionale Executablein org.junit.jupiter.api.

Fare riferimento :


1
In cima con questo! Questa è la migliore risposta di gran lunga la più aggiornata con JUnit 5. Inoltre, IntelliJ sta condensando ulteriormente la lambda se c'è solo una linea per la Lambda:assertThrows(NoSuchElementException.class, myLinkedList::getFirst);
anon58192932

26

L'hanno cambiato in JUnit 5 (previsto: InvalidArgumentException, attuale: metodo invocato) e il codice è simile al seguente:

@Test
public void wrongInput() {
    Throwable exception = assertThrows(InvalidArgumentException.class,
            ()->{objectName.yourMethod("WRONG");} );
}

21

Junit5 ora fornisce un modo per far valere le eccezioni

È possibile verificare sia le eccezioni generali che le eccezioni personalizzate

Uno scenario di eccezione generale:

ExpectGeneralException.java

public void validateParameters(Integer param ) {
    if (param == null) {
        throw new NullPointerException("Null parameters are not allowed");
    }
}

ExpectGeneralExceptionTest.java

@Test
@DisplayName("Test assert NullPointerException")
void testGeneralException(TestInfo testInfo) {
    final ExpectGeneralException generalEx = new ExpectGeneralException();

     NullPointerException exception = assertThrows(NullPointerException.class, () -> {
            generalEx.validateParameters(null);
        });
    assertEquals("Null parameters are not allowed", exception.getMessage());
}

È possibile trovare un esempio per testare CustomException qui: asserire un esempio di codice di eccezione

ExpectCustomException.java

public String constructErrorMessage(String... args) throws InvalidParameterCountException {
    if(args.length!=3) {
        throw new InvalidParameterCountException("Invalid parametercount: expected=3, passed="+args.length);
    }else {
        String message = "";
        for(String arg: args) {
            message += arg;
        }
        return message;
    }
}

ExpectCustomExceptionTest.java

@Test
@DisplayName("Test assert exception")
void testCustomException(TestInfo testInfo) {
    final ExpectCustomException expectEx = new ExpectCustomException();

     InvalidParameterCountException exception = assertThrows(InvalidParameterCountException.class, () -> {
            expectEx.constructErrorMessage("sample ","error");
        });
    assertEquals("Invalid parametercount: expected=3, passed=2", exception.getMessage());
}

1
Non c'è differenza nel modo in cui JUnit gestisce le eccezioni integrate e personalizzate.
raindev,

9

Penso che questo sia un esempio ancora più semplice

List<String> emptyList = new ArrayList<>();
Optional<String> opt2 = emptyList.stream().findFirst();
assertThrows(NoSuchElementException.class, () -> opt2.get());

Chiamare get()un opzionale contenente un vuoto ArrayListgenererà a NoSuchElementException. assertThrowsdichiara l'eccezione prevista e fornisce un fornitore lambda (non accetta argomenti e restituisce un valore).

Grazie a @prime per la sua risposta che spero di aver elaborato.


1
il metodo assertThrowsrestituisce l'eccezione generata. Quindi puoi fare come NoSuchElementException e = assertThrows(NoSuchElementException.class, () -> opt2.get());sotto quindi puoi fare qualsiasi tipo di asserzioni sull'oggetto eccezione che desideri.
Captain Man,

8

È possibile utilizzare assertThrows(). Il mio esempio è tratto dai documenti http://junit.org/junit5/docs/current/user-guide/

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

....

@Test
void exceptionTesting() {
    Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
        throw new IllegalArgumentException("a message");
    });
    assertEquals("a message", exception.getMessage());
}

2

Una fodera ancora più semplice. Non sono richieste espressioni lambda o parentesi graffe per questo esempio utilizzando Java 8 e JUnit 5

import static org.junit.jupiter.api.Assertions.assertThrows;

@Test
void exceptionTesting() {

    assertThrows(MyException.class, myStackObject::doStackAction, "custom message if assertion fails..."); 

// note, no parenthesis on doStackAction ex ::pop NOT ::pop()
}

1

In realtà penso che ci sia un errore nella documentazione per questo esempio particolare. Il metodo che si intende è prevede

public static void assertThrows(
public static <T extends Throwable> T expectThrows(

3
"Rimosso il metodo Assertions.expectThrows () deprecato a favore di Assertions.assertThrows ()."
Martin Schröder,

Per Junit 5, assicurati che provenga da org.junit.jupiter.api.Assertions e non da org.testng.Assert. Nel nostro progetto sono inclusi sia Junit che TestNG, e ho continuato a ricevere assertThrows restituisce un errore nullo fino a quando non l'ho modificato in assertExpects. Si è scoperto che stavo usando org.testng.Assert.
Barryku,

-5

Ecco un modo semplice.

@Test
void exceptionTest() {

   try{
        model.someMethod("invalidInput");
        fail("Exception Expected!");
   }
   catch(SpecificException e){

        assertTrue(true);
   }
   catch(Exception e){
        fail("wrong exception thrown");
   }

}

Ha successo solo quando viene generata l'eccezione che ti aspetti.

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.