lançar verificações de zombarias verificadas com Mockito

173

Estou tentando fazer com que um dos meus objetos zombados gere uma exceção verificada quando um método específico é chamado. Estou tentando o seguinte.

@Test(expectedExceptions = SomeException.class)
public void throwCheckedException() {
    List<String> list = mock(List.class);
    when(list.get(0)).thenThrow(new SomeException());
    String test = list.get(0);
}

public class SomeException extends Exception {
}

No entanto, isso produz o seguinte erro.

org.testng.TestException: 
Expected exception com.testing.MockitoCheckedExceptions$SomeException but got org.mockito.exceptions.base.MockitoException: 
Checked exception is invalid for this method!
Invalid: com.testing.MockitoCheckedExceptions$SomeException

Olhando para a documentação do Mockito , eles usam apenas RuntimeException, não é possível lançar exceções verificadas de um objeto simulado com o Mockito?

Arthur Maltson
fonte

Respostas:

221

Verifique a API Java para obter a lista .
O get(int index)método é declarado para lançar apenas o IndexOutOfBoundExceptionque se estende RuntimeException.
Você está tentando dizer ao Mockito para lançar uma exceção SomeException()que não é válida para ser lançada por essa chamada de método específica .

Para esclarecer mais.
A interface da lista não fornece uma exceção verificada a ser lançada do get(int index)método e é por isso que o Mockito está falhando.
Quando você cria a Lista zombada , o Mockito usa a definição de Lista .class para criar sua zombaria.

O comportamento que você está especificando com o when(list.get(0)).thenThrow(new SomeException()) não corresponde à assinatura do método na API de lista , porque o get(int index)método não éSomeException() acionado e o Mockito falha.

Se você realmente deseja fazer isso, faça com que o Mockito ative um new RuntimeException()ou, melhor ainda, ative a, new ArrayIndexOutOfBoundsException()pois a API especifica que essa é a única exceção válida a ser lançada.

John Engelman
fonte
Enquanto meu código real não estava realmente usando a Lista, sua resposta também se aplica a essa chamada de método. Eu estava zombando do método errado. Obrigado.
Arthur Maltson 21/09/10
2
Extra: Mocktio não vai reclamar se você doThrow um método sem quaisquer throwables, mas você também irá receber essa exceção
Dwana
8
Para Kotliners: o Kotlin não possui exceções verificadas, portanto você não pode normalmente declarar (na assinatura da função) que a função lança uma exceção. No entanto, você pode anotar a função com Throwsanotação para fazer com que o compilador gere o mesmo bytecode que declara lances no código Java equivalente. Veja [aqui] ( kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-throws/… ) para mais detalhes.
Javad Sadeqzadeh 4/10
1
Essa verificação é aplicada desde o lançamento do Mockito 2.11.0 (consulte 2.10.3) .
JJD
106

Uma solução alternativa é usar um willAnswer() método

Por exemplo, o seguinte funciona (e não lança um, MockitoExceptionmas realmente lança um verificado Exceptionconforme necessário aqui) usando BDDMockito:

given(someObj.someMethod(stringArg1)).willAnswer( invocation -> { throw new Exception("abc msg"); });

O equivalente a Mockito comum usaria o doAnswermétodo

Deepak
fonte
9
ou use willAnswer( invocation -> { throw new Exception("abc msg"); }).given(someObj).someMethod(stringArg1);quando o método retornar void.
Julien Kronegg
9
ou use when (someObj.someMethod (stringArg1)). thenAnswer (invocation -> {throw new Exception ("abc msg");});
Dmitri Algazin
Ótima solução alternativa, obrigado! Para os Kotliners que desejam (1) usar isso perfeitamente como uma função de extensão e (2) ser capaz de passar vários argumentos como willThrow()normalmente permite, escrevi um Gist
David Ferrand
2
ou doAnswerdenhaarman.mockitokotlin2
hmac 15/06
6

Note-se que, em geral, Mockito não permitir jogando exceções verificadas desde que a exceção é declarado na assinatura da mensagem. Por exemplo, dado

class BarException extends Exception {
  // this is a checked exception
}

interface Foo {
  Bar frob() throws BarException
}

é legal escrever:

Foo foo = mock(Foo.class);
when(foo.frob()).thenThrow(BarException.class)

No entanto, se você lançar uma exceção marcada não declarada na assinatura do método, por exemplo,

class QuxException extends Exception {
  // a different checked exception
}

Foo foo = mock(Foo.class);
when(foo.frob()).thenThrow(QuxException.class)

O Mockito falhará em tempo de execução com a mensagem genérica um tanto enganosa:

Checked exception is invalid for this method!
Invalid: QuxException

Isso pode levar você a acreditar que as exceções verificadas em geral não são suportadas, mas na verdade o Mockito está apenas tentando informar que essa exceção verificada não é válida para esse método .

David Moles
fonte
5

Existe a solução com o Kotlin:

given(myObject.myCall()).willAnswer {
    throw IOException("Ooops")
}

De onde vem o dado

import org.mockito.BDDMockito.given

Kevin ABRIOUX
fonte
1

Isso funciona para mim em Kotlin:

when(list.get(0)).thenThrow(new ArrayIndexOutOfBoundsException());

Nota: Lance qualquer exceção definida que não seja Exception ()

Alok Gupta
fonte
Exatamente o que eu estava procurando, pode lançar qualquer exceção que não sejaException
Naeem Sarfraz