Qual é a diferença entre zombar e espiar ao usar o Mockito?
137
Qual seria um caso de uso para o uso de um espião Mockito?
Parece-me que todo caso de uso de espião pode ser tratado com uma farsa, usando callRealMethod.
Uma diferença que posso ver é que, se você deseja que a maioria das chamadas de método seja real, ela salva algumas linhas de código para usar uma simulação contra um espião. É isso ou estou perdendo a foto maior?
Finalmente, após muitos debates internos e discussões na lista de discussão, foi adicionado suporte parcial a Mockito. Anteriormente, considerávamos zombarias parciais como odores de código. No entanto, encontramos um caso de uso legítimo para zombarias parciais.
Antes do release 1.8, o spy () não produzia zombarias parciais reais e era confuso para alguns usuários. Leia mais sobre espionagem: aqui ou no javadoc para o método spy (Object).
callRealMethod()foi introduzido depois spy(), mas spy () foi deixado lá, é claro, para garantir a compatibilidade com versões anteriores.
Caso contrário, você está certo: todos os métodos de um espião são reais, a menos que sejam esquecidos. Todos os métodos de um mock são stubbed, a menos que callRealMethod()sejam chamados. Em geral, eu preferiria usar callRealMethod(), porque não me força a usar o doXxx().when()idioma em vez do idioma tradicional.when().thenXxx()
O problema de preferir zombar do espião nesses casos é quando a classe usa um membro que não é injetado (mas inicializado localmente) e é usado posteriormente pelo método "real"; no mock, o membro será inicializado com seu valor Java padrão, o que pode causar um comportamento incorreto ou até uma NullPointerException. A maneira de passar isso é adicionar um método "init" e depois "realmente" chamá-lo, mas isso me parece um pouco exagerado.
Eyal Roth
No documento: "espiões devem ser usados com cuidado e ocasionalmente, por exemplo, ao lidar com código legado". O espaço de teste da unidade sofre muitas maneiras de fazer a mesma coisa.
Gdbj # 22/17
89
Diferença entre um Spy e um Mock
Quando o Mockito cria uma simulação - ele o faz a partir da Classe de um tipo, não de uma instância real. A zombaria simplesmente cria uma instância simples da Classe, totalmente instrumentada para rastrear interações com ela. Por outro lado, o espião quebra uma instância existente. Ele ainda se comportará da mesma maneira que a instância normal - a única diferença é que ele também será instrumentado para rastrear todas as interações com ele.
No exemplo a seguir - criamos uma simulação da classe ArrayList:
Como você pode ver - adicionar um elemento à lista zombada na verdade não adiciona nada - apenas chama o método sem nenhum outro efeito colateral. Um espião, por outro lado, se comportará de maneira diferente - na verdade, chamará a implementação real do método add e adicionará o elemento à lista subjacente:
Aqui certamente podemos dizer que o método interno real do objeto foi chamado porque, quando você chama o método size (), obtém o tamanho como 1, mas esse método size () não é ridicularizado! Então, de onde eu venho? O método interno real size () é chamado como size () não é zombado (ou stubbed) e, portanto, podemos dizer que a entrada foi adicionada ao objeto real.
No primeiro exemplo, por que mockedList.size()retornar 0se esse método também não foi excluído? Esse é apenas um valor padrão, dado o tipo de retorno do método?
Mike
@mike: mockedList.size()retorna um intvalor padrão de int0 em Java. Se você tentar executar assertEquals(0, mockedList.size());depois mockedList.clear();, o resultado permanecerá o mesmo.
realPK
2
Esta resposta está bem e simplesmente escrita e me ajudou a finalmente entender a diferença entre simulação e espião. Agradável.
PesaThe
38
Se houver um objeto com 8 métodos e você tiver um teste no qual deseja chamar 7 métodos reais e stub um método, você tem duas opções:
Usando um mock, você teria que configurá-lo chamando 7 callRealMethod e stub one method
Usando um, spyvocê deve configurá-lo stubbing um método
A documentação oficial sobre doCallRealMethodrecomenda o uso de um espião para zombarias parciais.
Veja também javadoc spy (Object) para descobrir mais sobre zombarias parciais. Mockito.spy () é uma maneira recomendada de criar simulações parciais. O motivo é que ele garante que métodos reais sejam chamados contra objetos construídos corretamente, porque você é responsável por construir o objeto passado para o método spy ().
Sim, você pode alterar para o primeiro código, mas a API é alterada. Se esse método estiver sendo usado por muitos lugares, você precisará alterar todos eles.
Alternativa é que você pode extrair a dependência assim:
Diferença entre um Spy e um Mock
Quando o Mockito cria uma simulação - ele o faz a partir da Classe de um tipo, não de uma instância real. A zombaria simplesmente cria uma instância simples da Classe, totalmente instrumentada para rastrear interações com ela. Por outro lado, o espião quebra uma instância existente. Ele ainda se comportará da mesma maneira que a instância normal - a única diferença é que ele também será instrumentado para rastrear todas as interações com ele.
No exemplo a seguir - criamos uma simulação da classe ArrayList:
Como você pode ver - adicionar um elemento à lista zombada na verdade não adiciona nada - apenas chama o método sem nenhum outro efeito colateral. Um espião, por outro lado, se comportará de maneira diferente - na verdade, chamará a implementação real do método add e adicionará o elemento à lista subjacente:
Aqui certamente podemos dizer que o método interno real do objeto foi chamado porque, quando você chama o método size (), obtém o tamanho como 1, mas esse método size () não é ridicularizado! Então, de onde eu venho? O método interno real size () é chamado como size () não é zombado (ou stubbed) e, portanto, podemos dizer que a entrada foi adicionada ao objeto real.
Fonte: http://www.baeldung.com/mockito-spy + notas próprias.
fonte
mockedList.size()
retornar0
se esse método também não foi excluído? Esse é apenas um valor padrão, dado o tipo de retorno do método?mockedList.size()
retorna umint
valor padrão deint
0 em Java. Se você tentar executarassertEquals(0, mockedList.size());
depoismockedList.clear();
, o resultado permanecerá o mesmo.Se houver um objeto com 8 métodos e você tiver um teste no qual deseja chamar 7 métodos reais e stub um método, você tem duas opções:
spy
você deve configurá-lo stubbing um métodoA documentação oficial sobre
doCallRealMethod
recomenda o uso de um espião para zombarias parciais.fonte
O espião pode ser útil quando você deseja criar testes de unidade para código legado .
Criei um exemplo executável aqui https://www.surasint.com/mockito-with-spy/ , copio alguns deles aqui.
Se você tiver algo parecido com este código:
Você pode não precisar de espionagem, porque pode apenas zombar de DepositMoneyService e WithdrawMoneyService.
Mas com alguns códigos herdados, a dependência está no código assim:
Sim, você pode alterar para o primeiro código, mas a API é alterada. Se esse método estiver sendo usado por muitos lugares, você precisará alterar todos eles.
Alternativa é que você pode extrair a dependência assim:
Então você pode usar o espião e injetar a dependência assim:
Mais detalhes no link acima.
fonte
Mock
é um objeto duplo simples. Este objeto tem as mesmas assinaturas de métodos, mas a realização está vazia e retorna o valor padrão - 0 e nuloSpy
é um objeto duplo clonado. O novo objeto é clonado com base em um objeto real, mas você tem a possibilidade de zombar dele[Teste tipos duplos]
fonte