首页 > 解决方案 > Mockito:验证是否执行了任何线程中指定的方法?

问题描述

我有一个类似以下的方法:

void enact(@NonNull final Request request) {
        XInput input = this.xBuilder.buildInputPayload(request);
        final Thread componentThread = new Thread(()->this.component.runJob(input));
        componentThread.start();
        return;    
}

void testVTService_Success() {
        when(xBuilder.buildInputPayload(any(Request.class))).thenReturn(inputPayloadWithAllArguments);
        activity.enact(TestConstants.request);
        verify(component, times(1)). runJob(any(XInput.class)); //Verification
    }

在验证 component.runJob() 方法正在执行时,它会抛出一个错误,指出 Wanted but not invoked: component.runJob() Actually, there were zero interactions with this mock.

我该如何解决?并验证线程是否正在启动并执行 runJob 方法?

标签: javajunitmockingmockito

解决方案


您的测试在一个线程上运行,而您的测试代码运行一个新线程。

这意味着runJob由于多线程,您的测试验证在方法之前运行。

那时测试说“想要但未调用”是正确的(测试代码运行,检查生产方法是否已经运行,它没有......然后在后台运行生产代码(为时已晚))。

理想情况下,您应该将线程控制与应用程序中的逻辑分开。包装Thread在 a 中ThreadFactory,对于真正的代码,您可以传递一个实际的线程,对于测试代码,您可以传递一个立即运行代码的对象(在同一个线程上)。

或者(不推荐)你破解你的测试(这将帮助你理解):

void testVTService_Success() {
    when(xBuilder.buildInputPayload(any(Request.class)))
    .thenReturn(inputPayloadWithAllArguments);

    activity.enact(TestConstants.request);

    try { Thread.sleep(TimeUnit.SECONDS.toMillis(10)); } catch (Exception e) { assertTrue(false); }

    verify(component, times(1)). runJob(any(XInput.class)); 
}

现在您的测试总是需要 10 秒,但希望生产代码不需要 10 秒即可完成执行?

这并不理想,就像我最初所说的那样,您希望将线程从该方法中拉出,将某种类型的工厂传递给类并在测试中传递一个 Fake 对象。(从而避免尝试测试多线程代码。)


推荐阅读