В чем разница между этими тремя подходами при создании тестов и имитации зависимостей?
@MockBean:
@MockBean MyService myservice;
@Mock:
@Mock MyService myservice;
Mockito.mock ()
MyService myservice = Mockito.mock(MyService.class);
Простая библиотека Mockito
import org.mockito.Mock;
...
@Mock
MyService myservice;
и
import org.mockito.Mockito;
...
MyService myservice = Mockito.mock(MyService.class);
происходят из библиотеки Mockito и функционально эквивалентны.
Они позволяют имитировать класс или интерфейс, а также записывать и проверять его поведение.
Использование аннотаций короче, поэтому предпочтительнее и часто предпочтительнее.
Обратите внимание, что для включения аннотаций Mockito во время выполнения тестов необходимо вызвать
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
.
Если в контексте существует bean-компонент, совместимый с объявленным классом, он заменяет его макетом.
Если это не так, он добавляет макет в контекст как bean-компонент.
Ссылка на Javadoc:
Аннотация, которую можно использовать для добавления фиктивных элементов в Spring ApplicationContext.
...
Если любой существующий одиночный компонент того же типа, который определен в контексте, будет заменен макетом, если существующий компонент не определен, будет добавлен новый.
Когда использовать классический / простой 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"));
}
}
@MockBean
заменит bean-компонент в контексте приложения, если bean-компонент, объявляющий тот же тип, уже определен в вашей конфигурации Spring. И инъекция выполняется в классе, в котором вы объявляете.@MockBean.
Механизмы DI работают следующим образом: вы регистрируете объект в контексте DI, а затем можете внедрить объект, на который имеется ссылка в контексте Spring, в конкретный класс. Вы не внедряете объект в контекст DI.В конце концов, это легко объяснить. Если вы просто заглянете в javadocs аннотаций, вы увидите разницу:
@Mock: (
org.mockito.Mock
)@MockBean: (
org.springframework.boot.test.mock.mockito.MockBean
)Mockito.mock ()
источник
@MockBean
и в@Mock
том, что один будет вводить макет в,Spring ApplicationContext
а другой - нет?