Mockito: дождитесь вызова, соответствующего аргументам

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

Поскольку это тест на селен, мне нужно дождаться запуска макета в другом потоке, поэтому я использую тайм-аут mockito.

verify(myMock, timeout(5000).times(1)).myMethod("expectedArg");

Проблема в том, что myMethod вызывается много раз... вместо ожидания вызова, соответствующего ожидаемым аргументам, тайм-аут ожидает только первый вызов. Если я использую Thread.sleep(50000), а не timeout(50000), он работает как положено... но это грязно, поэтому я надеюсь избежать этого.

Как мне ждать вызова myMethod с ожидаемым вводом?

2 ответа

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

import static org.hamcrest.CoreMatchers.hasItem;

@Captor ArgumentCaptor<String> arg;

@Before
public void setUp() throws Exception {
    // init the @Captor
    initMocks(this);
}

@Test
public void testWithTimeoutCallOrderDoesntMatter() throws Exception {
    // there must be exactly 99 calls
    verify(myMock, timeout(5000).times(99)).myMethod(arg.capture());
    assertThat(arg.getAllValues(), hasItem("expectedArg"));
}

Другой способ - указать все ожидаемые значения для проверки, но они должны быть предоставлены в точном порядке, в котором они вызываются. Отличие от вышеупомянутого решения состоит в том, что это не терпит неудачу, даже если макет дополнительно вызывается с некоторыми неподтвержденными аргументами. Другими словами, не нужно знать количество общих вызовов. Пример кода:

@Test
public void testWithTimeoutFollowingCallsDoNotMatter() throws Exception {
    // the order until expected arg is specific
    verify(callback, timeout(5000)).call("firstExpectedArg");
    verify(callback, timeout(5000)).call("expectedArg");
    // no need to tell more, if additional calls come after the expected arg
    // verify(callback, timeout(5000)).call("randomArg");
}

Это не супер чистое решение, но вы можете сделать это (XX это предполагаемый тип возврата здесь):

final CountDownLatch latch = new CountDownLatch(1);

doReturn(new Answer<XX>()
    {
        @Override
        public XX answer(InvocationOnMock invocation)
        {
            latch.countDown();
            return someInstanceOfXX;
        }
    }
).when(myMock).myMethod("expectedArg");

Затем, чтобы проверить, вызван ли метод, выполните:

try {
    assertTrue(latch.await(5L, TimeUnit.SECONDS));
} catch (InterruptedException e) {
    // Urgh... Failed. Deal with it and:
    Thread.currentThread.interrupt();
}
Другие вопросы по тегам