Eu sei que uma maneira de fazer isso seria:
@Test
public void foo(){
try{
//execute code that you expect not to throw Exceptions.
}
catch(Exception e){
fail("Should not have thrown any exception");
}
}
Existe alguma maneira mais limpa de fazer isso. (Provavelmente usando o Junit @Rule
?)
java
unit-testing
junit
exception-handling
junit4
Ankit Dhingra
fonte
fonte
Respostas:
Você está abordando isso da maneira errada. Apenas teste sua funcionalidade: se uma exceção for lançada, o teste falhará automaticamente. Se nenhuma exceção for lançada, todos os seus testes ficarão verdes.
Percebi que essa pergunta gera interesse de tempos em tempos, por isso vou expandir um pouco.
Antecedentes do teste de unidade
Quando você faz testes de unidade, é importante definir para si mesmo o que você considera uma unidade de trabalho. Basicamente: uma extração da sua base de código que pode ou não incluir vários métodos ou classes que representa uma única peça de funcionalidade.
Ou, conforme definido em The art of Unit Testing, 2ª edição de Roy Osherove , página 11:
O que é importante perceber é que uma unidade de trabalho geralmente não é apenas um método, mas no nível muito básico é um método e depois disso é encapsulado por outra unidade de obras.
Idealmente, você deve ter um método de teste para cada unidade de trabalho separada, para poder sempre ver imediatamente onde as coisas estão dando errado. Neste exemplo, existe um método básico chamado
getUserById()
que retornará um usuário e há um total de 3 unidades de obras.A primeira unidade de trabalho deve testar se um usuário válido está ou não sendo retornado no caso de entrada válida e inválida.
Quaisquer exceções que estão sendo lançadas pela fonte de dados devem ser tratadas aqui: se nenhum usuário estiver presente, deve haver um teste que demonstre que uma exceção será lançada quando o usuário não puder ser encontrado. Uma amostra disso pode ser a
IllegalArgumentException
que é capturada com a@Test(expected = IllegalArgumentException.class)
anotação.Depois de ter tratado todos os seus casos de uso para esta unidade básica de trabalho, você sobe de nível. Aqui você faz exatamente o mesmo, mas apenas lida com as exceções que vêm do nível logo abaixo do atual. Isso mantém seu código de teste bem estruturado e permite que você percorra rapidamente a arquitetura para descobrir onde as coisas dão errado, em vez de ter que pular por todo o lugar.
Manipulação de entrada válida e defeituosa de um teste
Neste ponto, deve ficar claro como vamos lidar com essas exceções. Existem 2 tipos de entrada: entrada válida e entrada com defeito (a entrada é válida no sentido estrito, mas não está correta).
Quando você trabalha com entrada válida, está definindo a expectativa implícita de que qualquer teste que você escrever funcionará.
Tal chamada de método pode ficar assim:
existingUserById_ShouldReturn_UserObject
. Se esse método falhar (por exemplo: uma exceção for lançada), você saberá que algo deu errado e poderá começar a cavar.Adicionando outro teste (
nonExistingUserById_ShouldThrow_IllegalArgumentException
) que usa a entrada defeituosa e espera uma exceção, você pode ver se o seu método faz o que é suposto fazer com a entrada incorreta.TL; DR
Você estava tentando fazer duas coisas em seu teste: verifique se há entradas válidas e com defeito. Dividindo isso em dois métodos, cada um fazendo uma coisa, você terá testes muito mais claros e uma visão geral muito melhor de onde as coisas dão errado.
Ao manter em mente a unidade de trabalho em camadas, você também pode reduzir a quantidade de testes necessários para uma camada que é mais alta na hierarquia, porque não é necessário contabilizar tudo o que pode ter dado errado nas camadas inferiores: o as camadas abaixo da atual são uma garantia virtual de que suas dependências funcionam e, se algo der errado, está na sua camada atual (supondo que as camadas inferiores não causem erros).
fonte
expected
anotação. Se você deseja testar um cenário em que seu código falha e deseja ver se o erro foi tratado corretamente: useexpected
e talvez use asserts para determinar se ele foi resolvido.throws IllegalArgumentException
ao seu teste. O que você deseja no final é que seu teste fique vermelho se houver uma exceção. Bem, adivinhe? Você não precisa escreverfail()
. Como escreveu @Jeroen Vannevel: "se uma exceção for lançada, o teste falhará automaticamente".Eu me deparei com isso por causa da regra "squid: S2699" do SonarQube: "Adicione pelo menos uma asserção a este caso de teste."
Eu fiz um teste simples, cujo único objetivo era passar sem lançar exceções.
Considere este código simples:
Que tipo de afirmação pode ser adicionada para testar esse método? Claro, você pode tentar o problema, mas isso é apenas o inchaço do código.
A solução vem da própria JUnit.
Caso nenhuma exceção seja lançada e você queira ilustrar explicitamente esse comportamento, basta adicionar
expected
como no exemplo a seguir:Test.None.class
é o padrão para o valor esperado.fonte
Com as assertivas fluentes do AssertJ 3.7.0 :
fonte
O JUnit 5 (Jupiter) fornece três funções para verificar a ausência / presença de exceção:
●
assertAll()
Afirma que todos os fornecidos
executables
não lançam exceções.
●
assertDoesNotThrow()
Afirma que a execução do
fornecido
executable
/supplier
não gera nenhum tipo de exceção .
Esta função está disponível
desde JUnit 5.2.0 (29 de abril de 2018).
●
assertThrows()
Indica que a execução do fornecido
executable
lança uma exceção
expectedType
e retorna a exceção .
Exemplo
fonte
O Java 8 facilita muito isso, e o Kotlin / Scala duplamente.
Podemos escrever uma pequena classe de utilidade
e então seu código se torna simplesmente:
Se você não tem acesso ao Java-8, eu usaria um recurso java dolorosamente antigo: blocos de códigos arbitrários e um simples comentário
E, finalmente, com o kotlin, uma linguagem pela qual me apaixonei recentemente:
Embora exista muito espaço para se mexer exatamente como você deseja expressar isso, eu sempre fui fã de afirmações fluentes .
A respeito de
Isso é correto em princípio, mas incorreto em conclusão.
Java permite exceções para o fluxo de controle. Isso é feito pelo próprio tempo de execução do JRE nas APIs, como
Double.parseDouble
via aNumberFormatException
ePaths.get
via aInvalidPathException
.Como você escreveu um componente que valida seqüências de números
Double.ParseDouble
, talvez usando um Regex, talvez um analisador escrito à mão ou talvez algo que incorpore outras regras de domínio que restrinjam o intervalo de um dobro a algo específico, qual a melhor forma de testar isso componente? Penso que um teste óbvio seria afirmar que, quando a string resultante é analisada, nenhuma exceção é lançada. Eu escreveria esse teste usando o bloco acimaassertDoesNotThrow
ou acima/*comment*/{code}
. Algo comoGostaria também de encorajá-lo a parametrizar este teste ao
input
usarTheories
ouParameterized
para que você possa reutilizar mais facilmente esse teste para outras entradas. Como alternativa, se você quiser ficar exótico, pode optar por uma ferramenta de geração de teste (e isso ). O TestNG tem melhor suporte para testes parametrizados.O que eu acho particularmente desagradável é a recomendação de uso
@Test(expectedException=IllegalArgumentException.class)
, essa exceção é perigosamente ampla . Se o seu código for alterado de forma que o componente sob o construtor do teste tenhaif(constructorArgument <= 0) throw IllegalArgumentException()
, e seu teste esteja fornecendo 0 para esse argumento por ser conveniente - e isso é muito comum, porque a boa geração de dados de teste é um problema surpreendentemente difícil -, seu teste será barra verde mesmo que não teste nada. Tal teste é pior que inútil.fonte
Assert.assertThrows
para verificar se algum código gera uma exceção.Se você tiver a sorte de detectar todos os erros no seu código. Você pode fazer estupidamente
fonte
Exception ex
deve ser= null;
antes que você possa testá-lo.JUnit5 adiciona o método assertAll () para essa finalidade exata.
fonte: API do JUnit 5
fonte
Embora este post tenha 6 anos, no entanto, muita coisa mudou no mundo do Junit. Com o Junit5, agora você pode usar
Ex:
Espero que ajude as pessoas que estão usando a versão mais recente do Junit5
fonte
Awaitility
éuntilAsserted(ThrowingRunnable assertion)
. Atualmente, o sistema em teste está lançando uma exceção específica no ThrowingRunnable que forneço, mas quero dar um tempo até que ele pare de fazê-lo. No entanto, se isso gerasse uma exceção diferente, gostaria que o teste falhasse instantaneamente.Se você deseja testar se o seu destino de teste consome a exceção. Apenas deixe o teste como (colaborador simulado usando jMock2):
O teste passaria se o seu destino consumisse a exceção lançada, caso contrário, o teste falharia.
Se você deseja testar sua lógica de consumo de exceção, as coisas ficam mais complexas. Sugiro delegar o consumo a um colaborador que pode ser ridicularizado. Portanto, o teste pode ser:
Mas, às vezes, é superprojetado, se você quiser apenas registrá-lo. Nesse caso, este artigo ( http://java.dzone.com/articles/monitoring-declarative-transac , http://blog.novoj.net/2008/09/09/20/testing-aspect-pointcuts-is-there -an-easy-way / ) pode ajudar se você insistir em tdd neste caso.
fonte
Use assertNull (...)
fonte
assertNull
nunca é executado. No entanto, o leitor rápido tem a impressão de que é feita uma afirmação que realmente verifica o caso que não é de lançamento. Em outras palavras: se o bloco catch for atingido, a exceção será sempre não nula - portanto, poderá ser substituída por uma simplesfail
.assertNull(e)
relatará o teste como falhou, como afirmadoe
não pode estarnull
nocatch
bloco ... Mike, isso é apenas uma programação estranha: - /. .. sim, pelo menos usofail()
como Andreas dizVocê pode esperar que a exceção não seja lançada criando uma regra.
fonte
Essa pode não ser a melhor maneira, mas definitivamente garante que a exceção não seja lançada no bloco de código que está sendo testado.
fonte
Você pode fazer isso usando uma @Rule e, em seguida, chame o método reportMissingExceptionWithMessage, conforme mostrado abaixo: Esse é o código Scala.
fonte
private val
? Qual é esse idioma? Claramente, não Java; p E, por favor, não forneça código como uma captura de tela, não é bem-vindo.O seguinte falha no teste de todas as exceções, marcadas ou desmarcadas:
fonte
Você pode criar qualquer tipo de suas próprias afirmações com base nas afirmações de junit:
E teste:
De um modo geral, existe a possibilidade de falhar instantaneamente ("bla bla bla") no teste em qualquer cenário, em qualquer lugar onde isso faça sentido. Por exemplo, use-o em um bloco try / catch para falhar se algo for lançado no caso de teste:
Esta é a amostra do método que testamos, supondo que tenhamos um método que não deve falhar em circunstâncias específicas, mas pode falhar:
O método acima é uma amostra simples. Mas isso funciona para situações complexas, nas quais a falha não é tão óbvia. Existem as importações:
fonte