Mockito: чем отличаются Mock и Spy?
Такой вопрос часто можно услышать на собеседовании, когда разговор заходит о 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 здесь.
Остались вопросы? Напишите в комментариях!