Разница между @Mock, @MockBean и Mockito.mock()

При создании тестов и издевательских зависимостей в чем разница между этими тремя подходами?

  1. @MockBean:

    @MockBean
    MyService myservice;
    
  2. @Mock:

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

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

Ответ 1

Обычная библиотека Mockito

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

а также

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

происходят из библиотеки Mockito и функционально эквивалентны.
Они позволяют издеваться над классом или интерфейсом, а также записывать и проверять поведение на нем.

Способ использования аннотации короче, поэтому предпочтительнее и часто предпочтительнее.


Обратите внимание, что для включения аннотаций Mockito во время тестовых исполнений необходимо MockitoAnnotations.initMocks(this) статический метод MockitoAnnotations.initMocks(this).
Чтобы избежать побочного эффекта между испытаниями, рекомендуется выполнить его перед каждым выполнением теста:

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

Еще один способ включить аннотации Mockito - аннотировать тестовый класс с помощью @RunWith, указав MockitoJUnitRunner который выполняет эту задачу, а также другие полезные вещи:

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

Библиотека загрузочной библиотеки Spring Boot Mockito

Это действительно класс Spring Boot:

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

Класс включен в библиотеку spring-boot-test.

Это позволяет добавлять Mockito mocks в Spring ApplicationContext.
Если в контексте существует компонент, совместимый с объявленным классом, он заменяет его макетом.
Если это не так, он добавляет макет в контексте в виде компонента.

Ссылка на Javadoc:

Аннотации, которые можно использовать для добавления mocks в Spring ApplicationContext.

...

Если какой-либо существующий один компонент одного и того же типа, определенный в контексте, будет заменен макетом, если никакой существующий bean-компонент не определен, будет добавлен новый.


Когда вы используете классический/простой Mockito и когда используете @MockBean из Spring Boot?

Модульные тесты предназначены для тестирования компонента в изоляции от других компонентов, а также для тестирования модулей также требуется: как можно быстрее с точки зрения времени выполнения, поскольку эти тесты могут выполняться каждый день десятками раз на машинах-разработчиках.

Следовательно, вот простое руководство:

Когда вы пишете тест, который не требует каких-либо зависимостей от контейнера Spring Boot, классический/простой Mockito - это способ следовать: он быстрый и способствует изоляции тестируемого компонента.
Если ваш тест должен опираться на контейнер Spring Boot, и вы хотите также добавить или издеваться над одним из контейнеров: @MockBean из Spring Boot - это путь.


Типичное использование Spring Boot @MockBean

Когда мы пишем тестовый класс, аннотированный с помощью @WebMvcTest (веб-тестовый фрагмент).

Документация Spring Boot очень хорошо описывает это:

Часто @WebMvcTest будет ограничиваться одним контроллером и использоваться в сочетании с @MockBean для предоставления макетных реализаций для требуемых соавторов.

Вот пример:

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"));
    }

}

Ответ 2

В конце его легко объяснить. Если вы просто посмотрите на javadocs аннотаций, вы увидите различия:

@Mock: (org.mockito.Mock)

Отметьте поле как макет.

  • Позволяет создавать сокращенные макеты.
  • Минимизирует повторяющийся код создания фальсификации.
  • Делает тестовый класс более удобочитаемым.
  • Делает ошибку проверки легче читать, потому что имя поля используется для идентификации макета.

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

Аннотации, которые можно использовать для добавления mocks в Spring ApplicationContext. Может использоваться в качестве аннотации уровня класса или по полям в классах @Configuration или тестовых классах, которые являются @RunWith.

Mocks может быть зарегистрирован по типу или по имени bean-компонента. Любой существующий один компонент одного и того же типа, определенный в контексте, будет заменен макетом, если никакой существующий bean-компонент не определен, новый будет добавлен.

Когда @MockBean используется в поле, а также регистрируется в контексте приложения, макет также будет введен в поле.

Mockito.mock()

Его просто представление @Mock.

Ответ 3

Единственное отличие, которое я вижу, заключается в том, что @Mock создает для смоделированного объекта значение по умолчанию этого класса, в то время как смоделированному объекту, созданному с помощью @MockBean по умолчанию, присваивается значение Null. Чтобы явно использовать то же самое в тестовом классе, нам нужно еще раз создать его экземпляр.