Mockito Test case for CompletableFuture.runAsync() 调用 void 方



我需要帮助为下面的方法编写模拟测试用例。

public void getCouponAndNotifyAsync(String countryId, String channelId,
        String storeNumber, String clientId, NotificationRequest notificationRequest)
        throws FirestoreException, TurneroServiceException {
    CompletableFuture.runAsync(() -> getCouponAndNotify(countryId, channelId,
            storeNumber, clientId, notificationRequest));
}

其中 getCouponAndNotify(( 是一个 void 方法。

在下面尝试过,但它不起作用

@Test
    public void getCouponAndNotifyAsync() throws Exception {
        //doNothing().when(turneroService).getCouponAndNotify(COUNTRYID, CHANNELID, STORENUMBER, CLIENTID, new NotificationRequest("ext_rborse@falabella.cl", "all"));
        CompletableFuture<Void> runAsync = CompletableFuture
                .runAsync(() -> doNothing().when(turneroService).getCouponAndNotify(COUNTRYID, CHANNELID, STORENUMBER, CLIENTID, new NotificationRequest("ext_rborse@falabella.cl", "all")));
        assertTrue(runAsync.isDone());
    }

更新了测试用例,但仍然无法正常工作。

@Test
    public void getCouponAndNotifyAsync() throws Exception {
        //doNothing().when(turneroService).getCouponAndNotify(COUNTRYID, CHANNELID, STORENUMBER, CLIENTID, new NotificationRequest("ext_rborse@falabella.cl", "all"));
        CompletableFuture<Void> runAsync = CompletableFuture
                .runAsync(() -> doNothing().when(turneroService).getCouponAndNotify(COUNTRYID, CHANNELID, STORENUMBER, CLIENTID, new NotificationRequest("ext_rborse@falabella.cl", "all")));
        assertTrue(ForkJoinPool.commonPool().awaitQuiescence(5, TimeUnit.SECONDS));
        assertTrue(runAsync.isDone());
    }

我假设您正在其他地方测试getCouponAndNotify(),因此您不必担心它会引发异常。

您将遇到的是getCouponAndNotifyAsync()getCouponAndNotify()返回之间的竞争条件。对此有几种解决方案:

由于您使用的是通用ForkJoinPool,因此请执行

assertTrue(ForkJoinPool.commonPool().awaitQuiescence(5, TimeUnit.Seconds));

它等待任务完成。

或者,您可以注入一个ExecutorService并将其用作supplyAsync()的第二个参数。您有几种选择:可以使用模拟,可以使用与当前线程一起运行的ExecutorService,也可以注入标准Executors.newSingleThreadExecutor(),然后在测试中调用shutdown()awaitTermination()

您还可以从getCouponAndNotifyAsync()返回可在测试中等待的CompletionStage<Void>

假设你有以下代码:

public void method() {
        CompletableFuture.runAsync(() -> {
            //logic
            //logic
            //logic
            //logic
        });
    }

尝试将其重构为如下所示的内容:

public void refactoredMethod() {
    CompletableFuture.runAsync(this::subMethod);
}
private void subMethod() {
    //logic
    //logic
    //logic
    //logic
}

之后,以这种方式测试子方法:

org.powermock.reflect.Whitebox.invokeMethod(classInstance, "subMethod"); 
Mockito.verify(...)

这不是一个完美的解决方案,但它测试了异步执行中的所有逻辑。

若要验证异步方法是否已调用,可以使用

 verify(<<your service>>, **timeout(100)**.times(1))
      .<<your method>>(<< arguments>>);

前任:-

verify(service, **timeout(100)**.times(1))
      .getCouponAndNotify(anyString(), anyString(), anyString(), anyString(), any(NotificationRequest.class));

请参阅 https://www.javadoc.io/doc/org.mockito/mockito-core/2.2.9/org/mockito/verification/VerificationWithTimeout.html

相关内容

  • 没有找到相关文章

最新更新