Начало работы с Mockito @Mock, @Spy, @Captor и @InjectMocks

Начало работы с Mockito @Mock, @Spy, @Captor и @InjectMocks

1. обзор

В этом руководстве мы рассмотримannotations of the Mockito library -@Mock,@Spy,@Captor и@InjectMocks.

Для получения дополнительных сведений о Mockito,have a look at the series here.

Дальнейшее чтение:

Мокито - Использование шпионов

Как правильно использовать шпионов в Mockito, и чем шпионы отличаются от насмешек.

Read more

Мокито против EasyMock против JMockit

Краткое и практическое руководство по пониманию и сравнению библиотек-макетов Java.

Read more

Инъекция Mockito Mocks в бобы

В этой статье будет показано, как использовать внедрение зависимостей для вставки макетов Mockito в Spring Beans для модульного тестирования.

Read more

2. Включить аннотации Mockito

Во-первых, давайте посмотрим, как включить использование аннотаций в тестах Mockito.

Чтобы эти аннотации были включены, нам потребуетсяannotate the JUnit test with a runner -MockitoJUnitRunner, как в следующем примере:

@RunWith(MockitoJUnitRunner.class)
public class MockitoAnnotationTest {
    ...
}

В качестве альтернативы, мы можем такжеenable these annotations programmatically, вызвавMockitoAnnotations.initMocks(), как в следующем примере:

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

3. @Mock Аннотация

Наиболее часто используемая аннотация в Mockito - это@Mock. Мы можем использовать@Mock для создания и внедрения имитированных экземпляров без необходимости вручную вызыватьMockito.mock.

В следующем примере мы создадим фиктивныйArrayList вручную без использования аннотации@Mock:

@Test
public void whenNotUseMockAnnotation_thenCorrect() {
    List mockList = Mockito.mock(ArrayList.class);

    mockList.add("one");
    Mockito.verify(mockList).add("one");
    assertEquals(0, mockList.size());

    Mockito.when(mockList.size()).thenReturn(100);
    assertEquals(100, mockList.size());
}

А теперь сделаем то же самое, но введем макет с аннотацией@Mock:

@Mock
List mockedList;

@Test
public void whenUseMockAnnotation_thenMockIsInjected() {
    mockedList.add("one");
    Mockito.verify(mockedList).add("one");
    assertEquals(0, mockedList.size());

    Mockito.when(mockedList.size()).thenReturn(100);
    assertEquals(100, mockedList.size());
}

Обратите внимание, как - в обоих примерах мы взаимодействуем с макетом и проверяем некоторые из этих взаимодействий - просто чтобы убедиться, что макет ведет себя правильно.

4. @Spy Аннотация

А теперь давайте посмотрим, как использовать аннотацию@Spy для отслеживания существующего экземпляра.

В следующем примере мы создаем шпионаList старым способом без использования аннотации@Spy:

@Test
public void whenNotUseSpyAnnotation_thenCorrect() {
    List spyList = Mockito.spy(new ArrayList());

    spyList.add("one");
    spyList.add("two");

    Mockito.verify(spyList).add("one");
    Mockito.verify(spyList).add("two");

    assertEquals(2, spyList.size());

    Mockito.doReturn(100).when(spyList).size();
    assertEquals(100, spyList.size());
}

Давайте теперь сделаем то же самое - проследим за списком - но сделаем это с помощью аннотации@Spy:

@Spy
List spiedList = new ArrayList();

@Test
public void whenUseSpyAnnotation_thenSpyIsInjectedCorrectly() {
    spiedList.add("one");
    spiedList.add("two");

    Mockito.verify(spiedList).add("one");
    Mockito.verify(spiedList).add("two");

    assertEquals(2, spiedList.size());

    Mockito.doReturn(100).when(spiedList).size();
    assertEquals(100, spiedList.size());
}

Обратите внимание, как, как и раньше, здесь мы взаимодействуем со шпионом, чтобы убедиться, что он ведет себя правильно. В этом примере мы:

  • Использовал методrealspiedList.add() для добавления элементов вspiedList.

  • Stubbed методspiedList.size() для возврата100 вместо2 с использованиемMockito.doReturn().

5. @Captor Аннотация

Далее - давайте посмотрим, как использовать аннотацию@Captor для создания экземпляраArgumentCaptor.

В следующем примере мы создаемArgumentCaptor старым способом без использования аннотации@Captor:

@Test
public void whenNotUseCaptorAnnotation_thenCorrect() {
    List mockList = Mockito.mock(List.class);
    ArgumentCaptor arg = ArgumentCaptor.forClass(String.class);

    mockList.add("one");
    Mockito.verify(mockList).add(arg.capture());

    assertEquals("one", arg.getValue());
}

Давайте теперьmake use of @Captor для той же цели - для создания экземпляраArgumentCaptor:

@Mock
List mockedList;

@Captor
ArgumentCaptor argCaptor;

@Test
public void whenUseCaptorAnnotation_thenTheSam() {
    mockedList.add("one");
    Mockito.verify(mockedList).add(argCaptor.capture());

    assertEquals("one", argCaptor.getValue());
}

Обратите внимание, как тест становится проще и удобнее для чтения, когда мы вынимаем логику конфигурации.

6. @InjectMocks Аннотация

Теперь - давайте обсудим, как использовать аннотацию@InjectMocks - для автоматического добавления ложных полей в тестируемый объект.

В следующем примере - мы используем@InjectMocks для внедрения фиктивногоwordMap вMyDictionarydic:

@Mock
Map wordMap;

@InjectMocks
MyDictionary dic = new MyDictionary();

@Test
public void whenUseInjectMocksAnnotation_thenCorrect() {
    Mockito.when(wordMap.get("aWord")).thenReturn("aMeaning");

    assertEquals("aMeaning", dic.getMeaning("aWord"));
}

А вот и классMyDictionary:

public class MyDictionary {
    Map wordMap;

    public MyDictionary() {
        wordMap = new HashMap();
    }
    public void add(final String word, final String meaning) {
        wordMap.put(word, meaning);
    }
    public String getMeaning(final String word) {
        return wordMap.get(word);
    }
}

7. Внедрение имитации шпиона

По аналогии с приведенным выше тестом, мы могли бы захотеть ввести шпион в шпион:

@Mock
Map wordMap;

@Spy
MyDictionary spyDic = new MyDictionary();

However, Mockito doesn’t support injecting mocks into spies,, и следующий тест приводит к исключению:

@Test
public void whenUseInjectMocksAnnotation_thenCorrect() {
    Mockito.when(wordMap.get("aWord")).thenReturn("aMeaning");

    assertEquals("aMeaning", spyDic.getMeaning("aWord"));
}

Если мы хотим использовать макет со шпионом, мы можем вручную вставить макет через конструктор:

MyDictionary(Map wordMap) {
    this.wordMap = wordMap;
}

Вместо того, чтобы использовать аннотацию, теперь мы можем создать шпиона вручную:

@Mock
Map wordMap;

MyDictionary spyDic;

@Before
public void init() {
    MockitoAnnotations.initMocks(this);
    spyDic = Mockito.spy(new MyDictionary(wordMap));
}

Тест сейчас пройдет.

8. Запуск NPE при использовании аннотации __

Часто мы можемrun into NullPointerException w, когда пытаемся фактически использовать экземпляр, помеченный@Mockor@Spy, как в примере:

public class NPETest {

    @Mock
    List mockedList;

    @Test
    public void test() {
        Mockito.when(mockedList.size()).thenReturn(1);
    }
}

В большинстве случаев это происходит просто потому, что мы забыли правильно включить аннотации Mockito.

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

9. Заметки

Наконец, вотsome notes об аннотациях Mockito:

  • Используйте аннотацию, чтобы минимизировать повторяющийся код создания макета

  • Используйте аннотацию, чтобы сделать тест более читабельным

  • Используйте@InjectMocks для внедрения экземпляров@Spy и@Mock

10. Заключение

В этом кратком руководстве мы показали основыannotations in the Mockito library.

Реализацию всех этих примеров можно найтиover on GitHub. Это проект Maven, поэтому его легко импортировать и запускать как есть.

И, конечно же, для большего удовольствия от Mockito,have a look at the series here.