【问题标题】:Is it possible to verify a mock method running in different thread in Mockito?是否可以验证在 Mockito 的不同线程中运行的模拟方法?
【发布时间】:2013-06-20 06:17:54
【问题描述】:

我有如下方法,

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


【解决方案1】:

很有可能Runnable在你验证调用的时候还没有被asyncTaskExecutor执行,导致你的单元测试出现验证错误。

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

如果您无法获取线程的实例,一种可能的解决方法是模拟 asyncTaskExecutor 并实现它,以便它直接执行可运行对象。

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】:

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

中使用参数 0
verify(someClass, timeout(0)).someMethod(any(someParameter.class));

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

【讨论】:

【解决方案3】:

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

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

【讨论】:

  • 你可以使用i,而不是(Answer&lt;Void&gt;)invocation
  • 对于any(Runnable.class),需要更换吗?或者您使用哪个导入来实现 any()?
【解决方案4】:

我花了几个小时才弄清楚发生了什么!我只是在调用被测方法之后和调用验证之前添加了 Thread.sleep。这将保证创建的线程在调用验证方法之前完成。

@Test
void testVerifyWorksForCodeRunsInThreads() {
    //given: 

    //when:
    //call the method under test which runs threads
    Thread.sleep(200);//MUST HAVE THIS BEFORE CALLING VERIFY TO MAKE SURE THE CREATED THREADS FINISH. Set the time based on how long your task would take

    //then: 
    verify(.......
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-21
    • 1970-01-01
    • 1970-01-01
    • 2022-09-28
    相关资源
    最近更新 更多