是否可以验证在Mockito中以不同线程运行的模拟方法?

问题描述 投票:15回答:3

我有一个像下面这样的方法,

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);

它给了我没有被调用。这是因为它是通过单独的线程调用的,是否可以验证在不同线程中调用的方法?

java mocking mockito powermock
3个回答
34
投票

当您验证调用时,Runnable很可能尚未被asyncTaskExecutor执行,从而导致单元测试中出现验证错误。

解决此问题的最佳方法是在验证调用之前加入生成的线程并等待执行。

如果你不能得到线程的实例,可能的解决方法是模拟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));
}

11
投票

我遇到了同样的问题并使用了超时参数http://javadoc.io/page/org.mockito/mockito-core/latest/org/mockito/Mockito.html#22但是使用了参数0

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

它有效。我假设测试线程产生,因此其他线程有机会完成其工作,适当地调用模拟。它仍然闻起来像一个黑客。


1
投票

为了进一步迭代Tom的答案 - 使用Java 8 Lambdas,您现在可以使用以下代码来模拟Executor,它稍微简洁一些:

    doAnswer((Answer<Void>)invocation -> {
        ((Runnable)invocation.getArgument(0)).run();
        return null;
    }).when(executorService).submit(any(Runnable.class));
© www.soinside.com 2019 - 2024. All rights reserved.