Diferença entre @Mock, @MockBean e Mockito.mock ()

147

Ao criar testes e zombar de dependências, qual é a diferença entre essas três abordagens?

  1. @MockBean:

    @MockBean
    MyService myservice;
    
  2. @Zombar:

    @Mock
    MyService myservice;
    
  3. Mockito.mock ()

    MyService myservice = Mockito.mock(MyService.class);
Doug
fonte

Respostas:

198

Biblioteca simples de Mockito

import org.mockito.Mock;
...
@Mock
MyService myservice;

e

import org.mockito.Mockito;
...
MyService myservice = Mockito.mock(MyService.class);

provêm da biblioteca Mockito e são funcionalmente equivalentes.
Eles permitem zombar de uma classe ou interface e registrar e verificar comportamentos nela.

A maneira como a anotação é mais curta, é preferível e geralmente preferida.


Observe que, para ativar as anotações do Mockito durante as execuções de teste, o MockitoAnnotations.initMocks(this)método estático deve ser chamado.
Para evitar efeitos colaterais entre os testes, é recomendável fazê-lo antes de cada execução de teste:

@Before 
public void initMocks() {
    MockitoAnnotations.initMocks(this);
}

Outra maneira de ativar as anotações do Mockito é fazer anotações na classe de teste @RunWithespecificando o MockitoJUnitRunnerque executa esta tarefa e também outras coisas úteis:

@RunWith(org.mockito.runners.MockitoJUnitRunner.class)
public MyClassTest{...}

Biblioteca Spring Boot envolvendo a biblioteca Mockito

Esta é realmente uma classe Spring Boot :

import org.springframework.boot.test.mock.mockito.MockBean;
...
@MockBean
MyService myservice;

A classe está incluída na spring-boot-testbiblioteca.

Permite adicionar zombarias de Mockito em uma mola ApplicationContext.
Se um bean compatível com a classe declarada existir no contexto, ele será substituído pelo mock.
Se não for o caso, ele adiciona a simulação no contexto como um bean.

Referência Javadoc:

Anotação que pode ser usada para adicionar zombarias a um Spring ApplicationContext.

...

Se qualquer bean único existente do mesmo tipo definido no contexto for substituído pelo mock, se nenhum bean existente for definido, um novo será adicionado.


Quando usar o Mockito clássico / comum e quando usar o @MockBeanSpring Boot?

Os testes de unidade são projetados para testar um componente isoladamente de outros componentes e os testes de unidade também têm um requisito: ser o mais rápido possível em termos de tempo de execução, pois esses testes podem ser executados diariamente dezenas de vezes nas máquinas do desenvolvedor.

Consequentemente, aqui está uma diretriz simples:

Ao escrever um teste que não precisa de nenhuma dependência do contêiner Spring Boot, o Mockito clássico / comum é o caminho a seguir: é rápido e favorece o isolamento do componente testado.
Se o seu teste precisar contar com o contêiner Spring Boot e você também quiser adicionar ou simular um dos beans do contêiner: a @MockBeanpartir do Spring Boot é o caminho.


Uso típico do Spring Boot @MockBean

Enquanto escrevemos uma classe de teste anotada com @WebMvcTest(fatia de teste da web).

A documentação do Spring Boot resume muito bem isso:

Freqüentemente @WebMvcTestserá limitado a um único controlador e usado em conjunto @MockBeanpara fornecer implementações simuladas para os colaboradores necessários.

Aqui está um exemplo :

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@RunWith(SpringRunner.class)
@WebMvcTest(FooController.class)
public class FooControllerTest {

    @Autowired
    private MockMvc mvc;

    @MockBean
    private FooService fooServiceMock;

    @Test
    public void testExample() throws Exception {
         Foo mockedFoo = new Foo("one", "two");

         Mockito.when(fooServiceMock.get(1))
                .thenReturn(mockedFoo);

         mvc.perform(get("foos/1")
            .accept(MediaType.TEXT_PLAIN))
            .andExpect(status().isOk())
            .andExpect(content().string("one two"));
    }

}
davidxxx
fonte
4
O uso do @MockBean criará uma cópia do bean e a injetará no ApplicationContext? Ou o bean zombado terá todos os seus métodos como nulos? Se todos os métodos forem nulos, posso removê-los como posso usar o @Mock?
Doug
6
Conforme explicado, o uso @MockBeansubstituirá o bean no contexto do aplicativo se um bean que declara o mesmo tipo já estiver definido na sua configuração do Spring. E a injeção é realizada na classe em que você declara @MockBean.Os mecanismos de DI funcionam desta maneira: você registra um objeto no contexto de DI e pode injetar o objeto referenciado no contexto de Spring em uma classe específica. Você não injeta um objeto no contexto de DI.
Davidxxx 26/05
13

No final, é fácil de explicar. Se você apenas olhar para os javadocs das anotações, verá os diferentes:

@Mock: ( org.mockito.Mock)

Marque um campo como uma farsa.

  • Permite criação falsa abreviada.
  • Minimiza o código repetitivo de criação simulada.
  • Torna a classe de teste mais legível.
  • Facilita a leitura do erro de verificação porque o nome do campo é usado para identificar a simulação.

@MockBean: ( org.springframework.boot.test.mock.mockito.MockBean)

Anotação que pode ser usada para adicionar zombarias a um Spring ApplicationContext. Pode ser usado como uma anotação no nível da classe ou em campos nas @Configurationclasses ou nas classes de teste que são @RunWitho SpringRunner.

As zombarias podem ser registradas por tipo ou nome do bean. Qualquer bean único existente do mesmo tipo definido no contexto será substituído pelo mock, se nenhum bean existente for definido, um novo será adicionado.

Quando @MockBeané usado em um campo, além de ser registrado no contexto do aplicativo, o mock também será injetado no campo.

Mockito.mock ()

É apenas a representação de um @Mock.

Patrick
fonte
5
Não vamos esquecer que o @Mock exige que o MockitoRunner ou initMocks seja chamado manualmente.
Florian Schaetz
4
A única diferença entre @MockBeane @Mockque um injetará o escárnio no Spring ApplicationContextoutro e o outro não?
Doug
3
@ Doug Você resumiu bem, mas é preciso lembrar que o MockBean faz parte do Spring Boot
comiventor