Можно ли проверить метод макета, выполняющийся в другом потоке в Mockito?

У меня есть метод, подобный следующему,

public void generateCSVFile(final Date billingDate) {
    asyncTaskExecutor.execute(new Runnable() {
        public void run() {
            try {
                accessService.generateCSVFile(billingDate);
            } catch (Exception e) {
                LOG.error(e.getMessage());
            }
        }
    });
}

Я высмеивал:

PowerMockito.doNothing().when(accessService).generateCSVFile(billingDate);

Но когда я проверяю:

verify(rbmPublicViewAccessService, timeout(100).times(1)).generateCSVFile(billingDate);

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

Ответ 1

Очень вероятно, что Runnable еще не был выполнен asyncTaskExecutor при проверке вызова, в результате чего в вашей unit test.

Лучший способ исправить это - присоединиться к сгенерированному потоку и дождаться выполнения перед проверкой вызовов.

Если вы не можете получить экземпляр потока, возможная работа заключается в том, чтобы издеваться над asyncTaskExecutor и реализовать его, чтобы он выполнял runnable напрямую.

private ExecutorService executor;

@Before
public void setup() {
    executor = mock(ExecutorService.class);
    implementAsDirectExecutor(executor);
}

protected void implementAsDirectExecutor(ExecutorService executor) {
    doAnswer(new Answer<Object>() {
        public Object answer(InvocationOnMock invocation) throws Exception {
            ((Runnable) invocation.getArguments()[0]).run();
            return null;
        }
    }).when(executor).submit(any(Runnable.class));
}

Ответ 2

У меня была такая же проблема и играли с аргументом таймаута http://javadoc.io/page/org.mockito/mockito-core/latest/org/mockito/Mockito.html#22 но с аргументом 0, как в

verify(someClass, timeout(0)).someMethod(any(someParameter.class));

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

Ответ 3

Для дальнейшей итерации ответа Тома - используя Java 8 Lambdas, теперь вы можете использовать следующий код для насмешки над Executor, который немного более лаконичен:

    doAnswer((Answer<Void>)invocation -> {
        ((Runnable)invocation.getArgument(0)).run();
        return null;
    }).when(executorService).submit(any(Runnable.class));