Como posso usar o JUnit4 por idioma para testar se algum código gera uma exceção?
Embora eu possa certamente fazer algo assim:
@Test
public void testFooThrowsIndexOutOfBoundsException() {
boolean thrown = false;
try {
foo.doStuff();
} catch (IndexOutOfBoundsException e) {
thrown = true;
}
assertTrue(thrown);
}
Lembro-me de que há uma anotação ou um Assert.xyz ou algo que é muito menos exigente e muito mais dentro do espírito da JUnit para esse tipo de situação.
org.mockito.Mockito.verify
com vários parâmetros para garantir que certas coisas aconteçam (como um serviço de logger foi chamado com os parâmetros corretos) antes que a exceção fosse lançada.Respostas:
Depende da versão do JUnit e do que afirmam as bibliotecas usadas.
A resposta original para
JUnit <= 4.12
foi:Embora a resposta https://stackoverflow.com/a/31826781/2986984 tenha mais opções para JUnit <= 4.12.
Referência:
fonte
ArrayList
que respondeget()
é irrelevante. Se eu escolhesse no futuro mudar para uma matriz primitiva, teria que alterar essa implementação de teste. A estrutura de dados deve estar oculta, para que o teste possa se concentrar no comportamento da classe .Edit: Agora que o JUnit 5 e o JUnit 4.13 foram lançados, a melhor opção seria usar
Assertions.assertThrows()
(para o JUnit 5) eAssert.assertThrows()
(para o JUnit 4.13). Veja minha outra resposta para obter detalhes.Se você não migrou para o JUnit 5, mas pode usar o JUnit 4.7, use a
ExpectedException
Regra:Isso é muito melhor do que
@Test(expected=IndexOutOfBoundsException.class)
porque o teste falhará seIndexOutOfBoundsException
for lançado antesfoo.doStuff()
Consulte este artigo para obter detalhes
fonte
ExpectedException
classe tem maneiras de corresponder à mensagem da exceção ou até de escrever seu próprio correspondente que depende da classe de exceção. Em segundo lugar, você pode definir sua expectativa imediatamente antes da linha de código que você espera lançar a exceção - o que significa que seu teste falhará se a linha de código errada lançar a exceção; considerando que não há como fazer isso com a solução de skaffman.Cuidado ao usar a exceção esperada, pois ela apenas afirma que o método lançou essa exceção, e não uma linha de código específica no teste.
Costumo usar isso para testar a validação de parâmetros, porque esses métodos geralmente são muito simples, mas testes mais complexos podem ser melhor atendidos com:
Aplique julgamento.
fonte
ExpectedException
, a coisa normal a fazer é definir a expectativa imediatamente antes da linha que você espera lançar a exceção. Dessa forma, se uma linha anterior lançar a exceção, ela não acionará a regra e o teste falhará.Como respondido anteriormente, existem muitas maneiras de lidar com exceções no JUnit. Mas com o Java 8, existe outro: usando o Lambda Expressions. Com as Expressões Lambda, podemos obter uma sintaxe como esta:
assertThrown aceita uma interface funcional, cujas instâncias podem ser criadas com expressões lambda, referências de método ou referências de construtor. assertThrown, aceitando essa interface, esperará e estará pronto para lidar com uma exceção.
Esta é uma técnica relativamente simples, mas poderosa.
Dê uma olhada nesta postagem do blog que descreve esta técnica: http://blog.codeleak.pl/2014/07/junit-testing-exception-with-java-8-and-lambda-expressions.html
O código fonte pode ser encontrado aqui: https://github.com/kolorobot/unit-testing-demo/tree/master/src/test/java/com/github/kolorobot/exceptions/java8
Divulgação: Sou o autor do blog e do projeto.
fonte
new DummyService()::someMethod
é umMethodHandle
, mas essa abordagem funciona igualmente bem com expressões lambda.em junho, há quatro maneiras de testar a exceção.
junit5.x
para junit5.x, você pode usar
assertThrows
o seguintejunit4.x
para junit4.x, use o atributo opcional 'esperado' da Teste de Anonação
para junit4.x, use a regra ExpectedException
você também pode usar a maneira clássica de try / catch amplamente usada na estrutura de 3 de junho
tão
para obter mais informações, você pode ler este documento e o guia do usuário do junit5 para obter detalhes.
fonte
Trowable
ao métodoExpectedException.expect
. por favor, veja a sua assinatura . @miusertl; dr
pós-JDK8: Use AssertJ ou lambdas customizadas para afirmar um comportamento excepcional .
pré-JDK8: Vou recomendar o velho bom
try
-catch
bloco. ( Não esqueça de adicionar umafail()
afirmação antes docatch
bloco )Independentemente do Junit 4 ou JUnit 5.
a longa história
É possível escrever você mesmo e fazê-lo
try
-catch
bloqueie ou use as ferramentas JUnit (@Test(expected = ...)
ou o@Rule ExpectedException
recurso de regra JUnit).Mas essas maneiras não são tão elegantes e não combinam bem a legibilidade com outras ferramentas. Além disso, as ferramentas JUnit têm algumas armadilhas.
O bloco
try
-catch
você deve escrever o bloco em torno do comportamento testado e escrever a asserção no bloco catch, isso pode ser bom, mas muitos acham que esse estilo interrompe o fluxo de leitura de um teste. Além disso, você precisa escrever umAssert.fail
no final dotry
bloco. Caso contrário, o teste pode perder um lado das afirmações; O PMD , o findbugs ou o Sonar identificarão esses problemas.O
@Test(expected = ...)
recurso é interessante, pois você pode escrever menos código e, em seguida, escrever esse teste é menos propenso a erros de codificação. Mas essa abordagem está faltando em algumas áreas.Além disso, como a expectativa é contida no método, dependendo de como o código testado é gravado, a parte errada do código de teste pode gerar a exceção, levando ao teste de falso positivo e não tenho certeza de que PMD , findbugs ou Sonar dará dicas sobre esse código.
A
ExpectedException
regra também é uma tentativa de corrigir as advertências anteriores, mas parece um pouco complicado de usar, pois usa um estilo de expectativa, os usuários do EasyMock conhecem muito bem esse estilo. Pode ser conveniente para alguns, mas se você seguir os princípios do Behavior Driven Development (BDD) ou do Organize Act Assert (AAA), aExpectedException
regra não se ajustará ao estilo de escrita. Além disso, ele pode sofrer do mesmo problema que o@Test
caminho, dependendo de onde você coloca a expectativa.Mesmo a exceção esperada é colocada antes da instrução de teste, ele interrompe o fluxo de leitura se os testes seguirem BDD ou AAA.
Veja também este comentário edição de no JUnit do autor de
ExpectedException
. O JUnit 4.13-beta-2 até deprecia este mecanismo:Portanto, essas opções acima têm toda sua carga de advertências e claramente não são imunes a erros de codificação.
Existe um projeto que eu tomei conhecimento depois de criar esta resposta que parece promissora, é uma exceção .
Como a descrição do projeto diz, ele permite que um codificador escreva em uma linha fluente de código capturando a exceção e ofereça essa exceção para a última afirmação. E você pode usar qualquer biblioteca de asserções como Hamcrest ou AssertJ .
Um exemplo rápido retirado da página inicial:
Como você pode ver que o código é realmente simples, você captura a exceção em uma linha específica, a
then
API é um alias que usará as APIs do AssertJ (semelhante ao usoassertThat(ex).hasNoCause()...
). Em algum momento, o projeto contou com o FEST-Assert, o ancestral do AssertJ . EDIT: Parece que o projeto está distribuindo um suporte ao Java 8 Lambdas.Atualmente, esta biblioteca possui duas deficiências:
No momento da redação deste artigo, é digno de nota que essa biblioteca é baseada no Mockito 1.x, pois cria uma simulação do objeto testado nos bastidores. Como o Mockito ainda não está atualizado, esta biblioteca não pode funcionar com classes ou métodos finais . E mesmo que fosse baseado no Mockito 2 na versão atual, isso exigiria declarar um criador de simulação global (
inline-mock-maker
), algo que pode não ser o que você deseja, pois esse criador de simulação tem desvantagens diferentes das do criador de simulação comum.Requer ainda outra dependência de teste.
Esses problemas não se aplicarão quando a biblioteca suportar lambdas. No entanto, a funcionalidade será duplicada pelo conjunto de ferramentas AssertJ.
Levando tudo em conta, se você não quiser usar a ferramenta catch-exception, vou recomendar a boa maneira antiga do bloco
try
-catch
, pelo menos até o JDK7. E para usuários do JDK 8, você pode preferir usar o AssertJ, pois oferece mais do que apenas declarar exceções.Com o JDK8, as lambdas entram em cena e provaram ser uma maneira interessante de afirmar um comportamento excepcional. O AssertJ foi atualizado para fornecer uma API fluente e agradável para afirmar um comportamento excepcional.
E um teste de amostra com AssertJ :
Com uma reescrita quase completa do JUnit 5, as asserções foram aprimoradas um pouco, elas podem ser interessantes como uma maneira pronta para afirmar uma exceção adequada. Mas realmente a API de afirmação ainda é um pouco ruim, não há nada lá fora
assertThrows
.Como você notou
assertEquals
ainda está voltandovoid
e, como tal, não permite asserções de encadeamento como o AssertJ.Além disso, se você se lembrar de um conflito de nome com
Matcher
ouAssert
, esteja preparado para enfrentar o mesmo conflito comAssertions
.Gostaria de concluir que hoje (03-03-2017) a facilidade de uso do AssertJ , a API detectável, o ritmo acelerado de desenvolvimento e como dependência de teste de fato são a melhor solução com o JDK8, independentemente da estrutura de teste (JUnit ou não), os JDKs anteriores deveriam confiar em
try
-catch
blocos mesmo que se sintam desajeitado.Esta resposta foi copiada de outra pergunta que não tem a mesma visibilidade, eu sou o mesmo autor.
fonte
Agora que o JUnit 5 e o JUnit 4.13 foram lançados, a melhor opção seria usar
Assertions.assertThrows()
(para o JUnit 5) eAssert.assertThrows()
(para o JUnit 4.13). Consulte o Guia do Usuário do Junit 5 .Aqui está um exemplo que verifica se uma exceção foi lançada e usa a Verdade para fazer afirmações na mensagem de exceção:
As vantagens sobre as abordagens nas outras respostas são:
throws
cláusulaUm método semelhante será adicionado
org.junit Assert
na JUnit 4.13.fonte
Que tal isso: Capture uma exceção muito geral, verifique se ela sai do bloco de captura e afirme que a classe da exceção é o que você espera que seja. Essa afirmação falhará se a) a exceção for do tipo errado (por exemplo, se você tiver um ponteiro nulo) eb) a exceção nunca foi lançada.
fonte
assertEquals(ExpectedException.class, e.getClass())
mostrará os valores reais e esperados quando o teste falhar.Solução estilo BDD : JUnit 4 + Exceção de captura + AssertJ
Dependências
fonte
Usando uma assertJ AssertJ , que pode ser usada ao lado do JUnit:
É melhor do que
@Test(expected=IndexOutOfBoundsException.class)
porque garante que a linha esperada no teste lançou a exceção e permite que você verifique mais detalhes sobre a exceção, como mensagem, mais fácil:Instruções Maven / Gradle aqui.
fonte
assertThat
, sempre o AssertJ. Além disso, o método JUnit retorna apenas um tipo "regular", enquanto o método AssertJ retorna umaAbstractAssert
subclasse ... permitindo a seqüência de métodos como acima (ou quaisquer que sejam os termos técnicos para isso ...).Para resolver o mesmo problema, montei um pequeno projeto: http://code.google.com/p/catch-exception/
Usando este pequeno ajudante, você escreveria
Isso é menos detalhado que a regra ExpectedException da JUnit 4.7. Em comparação com a solução fornecida pelo skaffman, você pode especificar em qual linha de código espera a exceção. Eu espero que isso ajude.
fonte
foo
éfinal
que irá falhar porque você não pode fazer proxyfoo
?Atualização: O JUnit5 possui uma melhoria para o teste de exceções:
assertThrows
.O exemplo a seguir é de: Guia do Usuário do Junit 5
Resposta original usando o JUnit 4.
Existem várias maneiras de testar se uma exceção é lançada. Eu também discuti as opções abaixo no meu post Como escrever ótimos testes de unidade com o JUnit
Defina o
expected
parâmetro@Test(expected = FileNotFoundException.class)
.Usando
try
catch
Testando com
ExpectedException
regra.Você pode ler mais sobre o teste de exceções no wiki do JUnit4 para Teste de exceção e bad.robot - Regra de JUnit de exceção de exceção .
fonte
Você também pode fazer isso:
fonte
Assert.fail()
, nãoassert
, apenas no caso de seus testes serem executados em um ambiente onde as asserções não estão ativadas.IMHO, a melhor maneira de verificar exceções no JUnit é o padrão try / catch / fail / assert:
O
assertTrue
pode ser um pouco forte para algumas pessoas, por isso,assertThat(e.getMessage(), containsString("the message");
pode ser preferível.fonte
Solução JUnit 5
Mais informações sobre o JUnit 5 em http://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions
fonte
expectThrows()
é uma parte TestNG, não uma JUnitA resposta mais flexível e elegante para o 4 de junho que encontrei no blog Mkyong . Tem a flexibilidade de
try/catch
usar a@Rule
anotação. Eu gosto dessa abordagem porque você pode ler atributos específicos de uma exceção personalizada.fonte
Tentei muitos dos métodos aqui, mas eles eram complicados ou não atendiam totalmente aos meus requisitos. De fato, pode-se escrever um método auxiliar de maneira bastante simples:
Use-o assim:
Zero dependências: sem necessidade de mockito, sem necessidade de powermock; e funciona muito bem com as aulas finais.
fonte
Solução Java 8
Se você deseja uma solução que:
Aqui está uma função utilitária que eu escrevi:
( retirado do meu blog )
Use-o da seguinte maneira:
fonte
A JUnit possui suporte interno para isso, com um atributo "esperado"
fonte
No meu caso, eu sempre recebo RuntimeException do db, mas as mensagens são diferentes. E a exceção precisa ser tratada respectivamente. Aqui está como eu testei:
fonte
} catch (
, você deve inserir #fail("no exception thrown");
Basta criar um Matcher que possa ser ligado e desligado, desta forma:
Para usá-lo:
adicione
public ExpectedException exception = ExpectedException.none();
, então:fonte
No JUnit 4 ou posterior, você pode testar as exceções da seguinte maneira
isso fornece muitos recursos que podem ser usados para melhorar nossos testes JUnit.
Se você vir o exemplo abaixo, estou testando três coisas na exceção.
fonte
Podemos usar uma falha de asserção após o método que deve retornar uma exceção:
fonte
catch
seria engolir o rastreamento de pilha se alguma outra exceção é lançada, perdendo informações úteisAlém do que o NamShubWriter disse, verifique se:
Você não fazer isso:
Por fim, esta postagem do blog ilustra claramente como afirmar que uma certa exceção é lançada.
fonte
Eu recomendo a biblioteca
assertj-core
para lidar com exceção no teste junitNo java 8, assim:
fonte
A solução Junit4 com Java8 é usar esta função:
O uso é então:
Observe que a única limitação é usar uma
final
referência de objeto na expressão lambda. Esta solução permite continuar as asserções de teste, em vez de esperar que sejam jogáveis no nível do método usando a@Test(expected = IndexOutOfBoundsException.class)
solução.fonte
Por exemplo, você quer escrever Junit para o fragmento de código abaixo mencionado
O código acima é para testar alguma exceção desconhecida que possa ocorrer e a abaixo é para declarar alguma exceção com mensagem personalizada.
fonte
Aqui está outra maneira de verificar o método gerado exceção correta ou não.
fonte
A estrutura JUnit possui o
assertThrows()
método:org.junit.jupiter.api.Assertions
sala de aula;org.junit.Assert
classe;org.junit.jupiter:junit-jupiter-api
ao seu projeto e você obterá uma versão perfeitamente funcional do JUnit 5.fonte
Com o Java 8, você pode criar um método usando um código para verificar e a exceção esperada como parâmetros:
e depois dentro do seu teste:
Benefícios:
fonte