【问题标题】:Mockito: Verify if a method specified in any thread got executed?Mockito:验证是否执行了任何线程中指定的方法?
【发布时间】:2021-11-03 08:55:45
【问题描述】:

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

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 方法?

【问题讨论】:

    标签: java junit mocking mockito


    【解决方案1】:

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

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

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

    理想情况下,您应该将线程控制与应用程序中的逻辑分开。将Thread 包裹在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 对象。 (从而避免尝试测试多线程代码。)

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多