JUnit 5: Como afirmar que uma exceção é lançada?


214

Existe uma maneira melhor de afirmar que um método lança uma exceção no JUnit 5?

Atualmente, tenho que usar uma @Rule para verificar se meu teste lança uma exceção, mas isso não funciona nos casos em que espero que vários métodos lançem exceções no meu teste.


1
você pode estar interessado em verificar o AssertJ para verificar exceções, pois é mais flexível que o JUnit5
user1075613

Respostas:


321

Você pode usar assertThrows(), o que permite testar várias exceções no mesmo teste. Com suporte para lambdas no Java 8, esta é a maneira canônica de testar exceções no JUnit.

De acordo com os documentos da 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
De uma velha escola "Eu não sei muito sobre o Junit5 e provavelmente não o suficiente sobre o Java8" ... isso parece bastante bizarro. Você se importaria de adicionar mais algumas explicações? como "qual parte existe o 'código de produção' real em teste ... que deveria ser lançado"?
GhostCat 26/10/16

1
() -> aponta para uma expressão lambda que aceita zero argumentos. Portanto, o "código de produção" que deve gerar a exceção está no bloco de código apontado (isto é, a throw new...instrução entre colchetes).
Sam Brannen

1
Normalmente, a expressão lambda interagia com o sujeito em teste (SUT). Em outras palavras, lançar uma exceção como acima é apenas para fins de demonstração.
Sam Brannen

1
Parece que o expectThrows foi descontinuado. Os documentos dizem usar assertThrows () agora.
depsypher

5
A partir da versão 5.0.0-M4, o expectThrows não está mais disponível. Somente assertThrows é permitido. Consulte github.com/junit-team/junit5/blob/master/documentation/src/docs/… : 'Removido o método Assertions.expectThrows () obsoleto em favor do Assertions.assertThrows ()'
gil.fernandes

91

No Java 8 e JUnit 5 (Jupiter), podemos afirmar exceções da seguinte maneira. Usandoorg.junit.jupiter.api.Assertions.assertThrows

estático público <T estende Throwable> T assertThrows (classe <T >pectedType, executável executável)

Indica que a execução do executável fornecido lança uma exceção do allowedType e retorna a exceção.

Se nenhuma exceção for lançada, ou se uma exceção de um tipo diferente for lançada, esse método falhará.

Se você não deseja executar verificações adicionais na instância de exceção, simplesmente ignore o valor de retorno.

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

Essa abordagem usará a interface funcional Executableno org.junit.jupiter.api.

Referir :


1
Para o topo com este! Esta é a melhor resposta, de longe, que é o mais up-to-date com JUnit 5. Além disso, IntelliJ é condensar o lambda ainda mais para baixo, se há apenas uma linha para o Lambda:assertThrows(NoSuchElementException.class, myLinkedList::getFirst);
anon58192932

26

Eles foram alterados no JUnit 5 (esperado: InvalidArgumentException, atual: método invocado) e o código se parece com este:

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

21

Agora o Junit5 fornece uma maneira de afirmar as exceções

Você pode testar exceções gerais e exceções personalizadas

Um cenário de exceção geral:

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());
}

Você pode encontrar uma amostra para testar a CustomException aqui: afirmar amostra de código de exceção

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
Não há diferença em como o JUnit lida com exceções internas e personalizadas.
raindev 24/11/19

9

Eu acho que este é um exemplo ainda mais simples

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

Chamar get()um opcional contendo um vazio ArrayListlançará a NoSuchElementException. assertThrowsdeclara a exceção esperada e fornece um fornecedor lambda (não aceita argumentos e retorna um valor).

Agradeço ao @prime por sua resposta na qual espero elaborar.


1
o método assertThrowsretorna a exceção lançada. Assim, você pode fazer o NoSuchElementException e = assertThrows(NoSuchElementException.class, () -> opt2.get());seguinte e fazer qualquer tipo de afirmação no objeto de exceção que deseja.
Capitão Man

8

Você pode usar assertThrows(). Meu exemplo é retirado dos documentos 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

Um forro ainda mais simples. Nenhuma expressão lambda ou chaveta necessária para este exemplo usando 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

Na verdade, acho que há um erro na documentação deste exemplo em particular. O método pretendido é expectThrows

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

3
"Removido o método Assertions.expectThrows () descontinuado em favor de Assertions.assertThrows ()."
Martin Schröder

Para o dia 5 de junho, verifique se é de org.junit.jupiter.api.Assertions e não org.testng.Assert. Nosso projeto inclui o Junit e o TestNG, e eu continuei recebendo assertThrows retorna um erro nulo até que eu o alterei para assertExpects. Acabou que eu estava usando org.testng.Assert.
barryku 16/06

-5

Aqui está uma maneira fácil.

@Test
void exceptionTest() {

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

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

}

Só é bem-sucedido quando a exceção que você espera é lançada.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.