Несколько дней новогоднего волшебства:
Успейте начать обучение в 2018-ом году со скидкой до 30%!
Выбрать курс

Mockito: чем отличаются Mock и Spy?

JavaDeep_5.06_Site.png

Такой вопрос часто можно услышать на собеседовании, когда разговор заходит о unit-тестировании. Mockito позволяет создать объект-заглушку для интерфейса или класса. В случае Mock-объекта, единственное, что будут делать все методы такого объекта, если не определять их поведение, – возвращать значения по-умолчанию: void, default-ы для примитивов, пустые коллекции и null для всех остальных объектов.

Но если какое-то поведение, требуемое для некоторых методов Mock-объекта, нам всё-таки нужно, мы можем его определить.

@RunWith(MockitoJUnitRunner.class)
public class MockTest {

    @Mock
    private Map<Integer, String> map;

    @Test
    public void testMockMapPutDefaultBehavior() {
        //when
        map.put(1, "test");

        //then
        assertThat(map.get(1), is(nullValue()));
    }

    @Test
    public void testMockMapKeySetDefaultBehavior() {
        //when
        map.put(1, "test");

        //then
        assertThat(map.keySet(), is(empty()));
    }

    @Test
    public void testMockMapValuesWithDefinedBehavior() {
        Collection<String> stub = Arrays.asList("test1", "test2", "test3");
        when(map.values()).thenReturn(stub);

        //when
        map.put(1, "test");

        //then
        assertThat(map.values(), is(stub));
    }

}

Помимо этого, Mockito позволяет «шпионить» за реальными объектами. В случае Spy-объекта, по-умолчанию будет исполняться оригинальное поведение методов объекта. Но как и в случае с Mock-объектами, их поведение можно переопределить.

@RunWith(MockitoJUnitRunner.class)
public class SpyTest {

    @Spy
    private Map<Integer, String> map = new HashMap<>();

    @Test
    public void testSpyMapPutDefaultBehavior() {
        //when
        map.put(1, "test");

        //then
        assertThat(map.get(1), is("test"));
    }

    @Test
    public void testSpyMapKeySetDefaultBehavior() {
        //when
        map.put(1, "test1");
        map.put(2, "test2");

        //then
        assertThat(map.keySet(), containsInAnyOrder(1, 2));
    }

    @Test
    public void testSpyMapValuesWithDefinedBehavior() {
        Collection<String> stub = Arrays.asList("test1", "test2", "test3");
        when(map.values()).thenReturn(stub);

        //when
        map.put(1, "test");

        //then
        assertThat(map.values(), is(stub));
    }

}

Если мы хотим протестировать логику самого объекта и при этом не хотим внедрять какие-либо реальные сервисы и компоненты, то в данном случае стоит использовать вместо них Mock-объекты. В случае, если мы хотим протестировать всё вместе, за исключением каких-то специфических случаев, то стоит использовать Spy.

Ссылка на GitHub здесь.

Остались вопросы? Напишите в комментариях!

Автор
2 комментария
1

Почему примеры кода для Mock и Stub одинаковые?

0

Поправили, спасибо!

Для комментирования необходимо авторизоваться