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.