12

Как замокировать методы с возвращаемым типом void с помощью Mockito

17

Как замокировать методы с возвращаемым типом void?

Я реализовал паттерн наблюдатель, но не могу замокировать его с помощью Mockito, потому что не знаю, как это сделать.

Я пытался найти пример в интернете, но не смог.

Мой класс выглядит следующим образом:

public class World {

    List<Listener> listeners;

    void addListener(Listener item) {
        listeners.add(item);
    }

    void doAction(Action goal, Object obj) {
        setState("я получил");
        goal.doAction(obj);
        setState("я закончил");
    }

    private String state;
    // сеттер и геттер для state
} 

public class WorldTest implements Listener {

    @Test public void word() {
        World w = mock(World.class);
        w.addListener(this);
        ...
        ...
    }
}

interface Listener {
    void doAction();
}

Система не вызывается с мок-объектом.

Я хочу отобразить состояние вышеупомянутой системы и сделать утверждения в соответствии с ними.

5 ответ(ов)

1

Я думаю, что нашёл более простой ответ на этот вопрос. Чтобы вызвать реальный метод для одного конкретного метода (даже если он имеет возвращаемое значение void), вы можете сделать так:

Mockito.doCallRealMethod().when(<objectInstance>).<method>();
<objectInstance>.<method>();

Или, если вы хотите вызывать реальные методы для всех методов этого класса, можно сделать следующее:

<Object> <objectInstance> = mock(<Object>.class, Mockito.CALLS_REAL_METHODS);
1

Добавляя к тому, что сказал @sateesh, если вам нужно замокировать метод без возвращаемого значения (void), чтобы предотвратить его вызов в тесте, вы можете использовать Spy следующим образом:

World world = new World();
World spy = Mockito.spy(world);
Mockito.doNothing().when(spy).methodToMock();

Когда вы будете запускать свой тест, убедитесь, что метод вызывается на объекте spy, а не на объекте world. Например:

assertEquals(0, spy.methodToTestThatShouldReturnZero());

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

0

Во-первых, всегда импортируйте статические методы Mockito, так ваш код будет гораздо более читаемым и интуитивно понятным:

import static org.mockito.Mockito.*;

Для частичного мокирования, сохраняя при этом оригинальную функциональность, Mockito предлагает использовать "Spy".

Вы можете сделать это следующим образом:

private World world = spy(new World());

Чтобы предотвратить выполнение определенного метода, вы можете использовать что-то вроде этого:

doNothing().when(someObject).someMethod(anyObject());

Для добавления кастомного поведения к методу используйте "when" с "thenReturn":

doReturn("something").when(this.world).someMethod(anyObject());

Для получения дополнительных примеров, пожалуйста, ознакомьтесь с отличными примерами Mockito в документации.

0

В Java 8 это можно сделать чуть чище, если вы используете статический импорт для org.mockito.Mockito.doAnswer:

doAnswer(i -> {
  // Здесь выполняем действия с i.getArguments()
  return null;
}).when(*mock*).*method*(*methodArguments*);

Важно, чтобы return null; присутствовал, так как без него компиляция завершится с довольно неясными ошибками, поскольку компилятор не сможет найти подходящий переопределяемый метод для doAnswer.

Например, интерфейс ExecutorService, который просто немедленно выполняет любой Runnable, переданный в метод execute(), можно реализовать следующим образом:

doAnswer(i -> {
  ((Runnable) i.getArguments()[0]).run();
  return null;
}).when(executor).execute(any());
0

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

Если вы реализуете слушателя как мок, вы сможете проверить взаимодействие.

Listener listener = mock(Listener.class);
w.addListener(listener);
world.doAction(..);
verify(listener).doAction();

Это должно подтвердить, что 'World' выполняет правильные действия.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь