Mockito - diferença entre doReturn () e quando ()

196

Atualmente, estou no processo de usar o Mockito para simular meus objetos da camada de serviço em um aplicativo Spring MVC no qual desejo testar meus métodos do Controller. No entanto, como eu tenho lido sobre as especificidades do Mockito, descobri que os métodos doReturn(...).when(...)são equivalentes when(...).thenReturn(...). Então, minha pergunta é: qual é o sentido de ter dois métodos que fazem a mesma coisa ou qual é a diferença sutil entre doReturn(...).when(...)ewhen(...).thenReturn(...) ?

Qualquer ajuda seria apreciada.

Pantera negra
fonte
1
O javadoc tem alguns casos em que doReturn()é útil.
Sotirios Delimanolis
5
Eu acho que uma das principais diferenças é que doReturn (...). Quando (..) é mais antigo e não é desse tipo seguro e, portanto, podemos usá-lo algumas vezes quando o compilador continua reclamando sobre a transmissão. O when (..) thenReturn (..) é muito melhor em termos de segurança de tipo
user2511882

Respostas:

227

As duas sintaxes para stub são aproximadamente equivalentes. No entanto, você sempre pode usar doReturn/whenpara stubbing; mas há casos em que você não pode usar when/thenReturn. Stubbing void methods é um desses. Outros incluem o uso de espiões de Mockito e a remoção do mesmo método mais de uma vez.

Uma coisa que when/thenReturnte dá, quedoReturn/when e não fornece, é a verificação de tipo do valor que você está retornando, no momento da compilação. No entanto, acredito que isso quase não tem valor - se você errou o tipo, descobrirá assim que executar o teste.

Eu recomendo fortemente apenas o uso doReturn/when. Não há sentido em aprender duas sintaxes quando uma delas funciona.

Você pode consultar a minha resposta em Formando Mockito "gramáticas" - uma resposta mais detalhada a uma questão muito relacionada.

Dawood ibn Kareem
fonte
16
Eu meio que discordo de David. Muitas vezes, encontro situações em que retorno o tipo errado ao usar doReturn/whene passo os próximos minutos descobrindo o que deu errado. A verificação de tipo de tipo de compilação se torna extremamente útil when/thenReturn.
Saket 15/02
11
Lembre-se de que a Mockito recomenda o uso em when/thenReturnvez de doReturn/when.
CodyEngel
2
@CodyEngel e não há motivo para tal recomendação, além do que descrevi em minhas respostas aqui e em stackoverflow.com/q/11462697 . Há vários anos, discuti isso com Brice Dutheil, que atualmente está atuando como desenvolvedor líder do Mockito, e, até onde sei, ele concorda. Vou pedir para ele postar um comentário aqui (não há garantia de que ele fará isso).
Dawood ibn Kareem
18
O javadoc afirma que isso doReturn/whené uma troca. A equipe não recomenda de uma maneira ou de outra, mas observe que a when/thenabordagem é mais intuitiva, mais legível e oferece verificação do tempo de compilação; foi a abordagem que tornou o Mockito popular e fácil de usar, não se esqueça que, quando o código base é compartilhado por várias habilidades em sua equipe; no entanto, há desvantagens em relação a espiões e métodos vazios.
Brice
5
Apenas para constar: doReturn()tem a grande desvantagem de se transformar na codificação no estilo YODA de chamadas de método. A coisa que vem depois é escrita primeiro. A maioria das pessoas lê da esquerda para a direita; agora você precisa se lembrar constantemente de reverter a lógica do retorno quando em sua cabeça.
GhostCat 24/02
199

Ambas as abordagens se comportam de maneira diferente se você usar um objeto espionado (anotado com @Spy) em vez de um mock (anotado com @Mock):

  • when(...) thenReturn(...) faz uma chamada de método real pouco antes do valor especificado ser retornado. Portanto, se o método chamado lança uma exceção, você precisa lidar com isso / zombar etc. É claro que você ainda obtém seu resultado (o que você define thenReturn(...))

  • doReturn(...) when(...) não chama o método .

Exemplo:

public class MyClass {
     protected String methodToBeTested() {
           return anotherMethodInClass();
     }

     protected String anotherMethodInClass() {
          throw new NullPointerException();
     }
}

Teste:

@Spy
private MyClass myClass;

// ...

// would work fine
doReturn("test").when(myClass).anotherMethodInClass();

// would throw a NullPointerException
when(myClass.anotherMethodInClass()).thenReturn("test");
akcasoy
fonte
37
Esse comportamento funciona apenas para objetos espionados, pois são "invólucros" de objetos reais. No caso de objetos simulados, não importa se é quando / thenReturn ou doReturn / when. Objetos simulados nunca chamam métodos reais.
Rafael Orágio
Você poderia fornecer mais informações, por que precisamos usar essa funcionalidade? Não vejo casos de uso práticos. A intenção do teste é confirmar a correção do código em diferentes casos de uso. Se o calll do método lança teste de exceção deve jogar exceção, não retornar um valor
Gleichmut
@Gleichmut Este foi um cenário hipotético, onde mostro o uso / vantagem do doReturn. Em um aplicativo real, um método que retorna apenas uma exceção torna claro nenhum sentido .. mas você tem métodos (provavelmente não tão fina como este) que podem lançar exceções em determinadas condições ..
akcasoy
1
Apenas para esclarecimento: O método when (). ThenReturn () chama o método real (de um espião - não importa para zombarias) apenas uma vez. Isso acontece na linha em que você especifica o comportamento simulado (when ( myClass.anotherMethodInClass () .thenRet ...). Depois disso, o método real nunca é chamado novamente. Talvez seja bom saber se você esperava alguma lógica do decorador ao ler a explicação acima.
Jonas
Isso não parece uma vantagem doReturn(), parece um abuso da biblioteca. O ponto de espionagem em vez de pura zombaria é tirar proveito de chamadas reais. Eles também alertam contra o uso de Spies como este: github.com/mockito/mockito/wiki/Using-Spies-(and-Fakes) (e recomendam estender a classe e substituir o método)
Matthew Read
13

O javadoc do Mockito parece dizer por que usar em doReturn()vez de when() Usar doReturn () nas raras ocasiões em que você não pode usar o Mockito.when (Object).

Lembre-se de que Mockito.when (Object) é sempre recomendado para stubbing porque é seguro para o tipo de argumento e mais legível (especialmente ao stubing de chamadas consecutivas).

Aqui estão aquelas raras ocasiões em que doReturn () é útil:

1. Espiar objetos reais e chamar métodos reais em um espião traz efeitos colaterais

List list = new LinkedList(); List spy = spy(list);

// Impossível: método real é chamado para que spy.get (0) lança IndexOutOfBoundsException (a lista ainda está vazia)

when(spy.get(0)).thenReturn("foo");

// Você precisa usar doReturn () para stub: doReturn("foo").when(spy).get(0);

2. Substituindo um stub de exceção anterior:

when(mock.foo()).thenThrow(new RuntimeException());

// Impossível: o método foo () com exceção de stubbed é chamado para que RuntimeException seja lançada. when(mock.foo()).thenReturn("bar");

// Você precisa usar doReturn () para stub:

doReturn("bar").when(mock).foo(); Os cenários acima mostram uma troca da elegante sintaxe de Mockito. Observe que os cenários são muito raros, no entanto. A espionagem deve ser esporádica e a substituição de exceções é muito rara. Sem mencionar que, em geral, a substituição de stubbing é um cheiro de código em potencial que aponta muitos stubbing.


fonte
6

Continuando com esta resposta , há outra diferença: se você deseja que seu método retorne valores diferentes, por exemplo, quando é chamado pela primeira vez, chamado pela segunda vez, etc., você pode passar valores, por exemplo ...

PowerMockito.doReturn(false, false, true).when(SomeClass.class, "SomeMethod", Matchers.any(SomeClass.class));

Portanto, ele retornará falso quando o método for chamado no mesmo caso de teste e, em seguida, retornará falso novamente e, finalmente, verdadeiro.

AZ_
fonte