Как сделать методы mock to void с помощью mockito

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

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

и я попытался найти пример в интернете, но не удалось.

мой класс выглядит так:

public class World {

    List<Listener> listeners;

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

    void doAction(Action goal,Object obj) {
        setState("i received");
        goal.doAction(obj);
        setState("i finished");
    }

    private string state;
    //setter getter state
} 

public class WorldTest implements Listener {

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

    }
}

interface Listener {
    void doAction();
}

система не запускается с помощью mock. =( Я хочу показать вышеупомянутое состояние системы. И утверждайте согласно им.

10 ответов


взгляните на Mockito API docs. Как упоминает связанный документ (пункт # 12), вы можете использовать любой из doThrow(),doAnswer(),doNothing(),doReturn() семейство методов от Mockito framework до методов mock void.

например,

Mockito.doThrow(new Exception()).when(instance).methodName();

или если вы хотите объединить его с последующими поведения,

Mockito.doThrow(new Exception()).doNothing().when(instance).methodName();

предполагая, что вы смотрите на издевательство над сеттером setState(String s) в мире классов ниже код использует doAnswer способ издеваться над setState.

World  mockWorld = mock(World.class); 
doAnswer(new Answer<Void>() {
    public Void answer(InvocationOnMock invocation) {
      Object[] args = invocation.getArguments();
      System.out.println("called with arguments: " + Arrays.toString(args));
      return null;
    }
}).when(mockWorld).setState(anyString());

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

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

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

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

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

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

когда вы хотите запустить тест, убедитесь, что вы вызываете метод в тесте на


решение так называемой проблемы заключается в использовании spy Mockito.шпион.(..) вместо mock Mockito.издеваться.(.).

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


прежде всего: вы всегда должны импортировать Mockito static, таким образом, код будет гораздо более читаемым (и интуитивно понятным):

import static org.mockito.Mockito.*;

для частичного издевательства и сохранения оригинальной функциональности на остальных mockito предлагает "шпион".

вы можете использовать его следующим образом:

private World world = spy(World.class);

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

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

чтобы дать некоторое пользовательское поведение методу, используйте "когда" с "thenReturn":

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

для Больше примеров пожалуйста найдите образцы mockito в doc.


как издеваться над методами void с mockito - есть два варианта:

  1. doAnswer - Если мы хотим, чтобы наш издевательский метод void что-то сделал (издевайтесь над поведением, несмотря на пустоту).
  2. doThrow - то есть Mockito.doThrow() Если вы хотите создать исключение из метода mocked void.

Ниже приведен пример того, как его использовать (не идеальный usecase, но просто хотел проиллюстрировать основные использование.)

@Test
public void testUpdate() {

    doAnswer(new Answer<Void>() {

        @Override
        public Void answer(InvocationOnMock invocation) throws Throwable {
            Object[] arguments = invocation.getArguments();
            if (arguments != null && arguments.length > 1 && arguments[0] != null && arguments[1] != null) {

                Customer customer = (Customer) arguments[0];
                String email = (String) arguments[1];
                customer.setEmail(email);

            }
            return null;
        }
    }).when(daoMock).updateEmail(any(Customer.class), any(String.class));

    // calling the method under test
    Customer customer = service.changeEmail("old@test.com", "new@test.com");

    //some asserts
    assertThat(customer, is(notNullValue()));
    assertThat(customer.getEmail(), is(equalTo("new@test.com")));

}

@Test(expected = RuntimeException.class)
public void testUpdate_throwsException() {

    doThrow(RuntimeException.class).when(daoMock).updateEmail(any(Customer.class), any(String.class));

    // calling the method under test
    Customer customer = service.changeEmail("old@test.com", "new@test.com");

}
}

вы можете найти более подробную информацию о том, как mock и тест пустота методы с Mockito в моем посте как издеваться с Mockito (полное руководство с примерами)


добавление другого ответа в кучу (каламбур не предназначен)...

вам нужно вызвать метод doAnswer, если вы не можете\не хотите использовать spy's. Тем не менее, вам не обязательно катить свой собственный ответ. Существует несколько реализаций по умолчанию. В частности, CallsRealMethods.

на практике, это выглядит примерно так:

doAnswer(new CallsRealMethods()).when(mock)
        .voidMethod(any(SomeParamClass.class));

или:

doAnswer(Answers.CALLS_REAL_METHODS.get()).when(mock)
        .voidMethod(any(SomeParamClass.class));

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

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

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

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

doAnswer(i -> {
  // Do stuff with i.getArguments() here
  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());

@ashley: работает на меня

public class AssetChangeListenerImpl extends
AbstractAssetChangeListener implements AssetChangeListener {

  @Override
  public void onChangeEvent(final EventMessage message) throws EventHubClientException {
      execute(message);
    }
  }
}

public class AbstractAssetChangeListener {
  protected  void execute( final EventMessage message ) throws EventHubClientException {
    executor.execute( new PublishTask(getClient(), message) );
} } @RunWith(MockitoJUnitRunner.class) public class AssetChangeListenerTest extends AbstractAssetChangeListenerTest {

 public void testExecute() throws EventHubClientException {
    EventMessage message = createEventMesage(EventType.CREATE);
    assetChangeListener.execute(message);
    verify(assetChangeListener, times(1)).execute(message);
} }