如何通过避免手动睡眠来对 CompletableFuture.thenAccept() 进行单元测试

How to unit test CompletableFuture.thenAccept() by avoiding manual sleep

如何在单元测试中避免手动休眠。 假设在下面的代码中,Processnotify 需要大约 5 秒的处理时间。所以为了完成处理,我增加了 5 秒的睡眠时间。

public class ClassToTest {

    public ProcessService processService;
    public NotificationService notificationService;

    public ClassToTest(ProcessService pService ,NotificationService nService ) {
        this.notificationService=nService;
        this.processService = pService;
    }
    public CompletableFuture<Void> testMethod()
    {
          return CompletableFuture.supplyAsync(processService::process)
                        .thenAccept(notificationService::notify);
    }

}

有没有更好的方法来处理这个问题?

 @Test
    public void comletableFutureThenAccept() {
         CompletableFuture<Void> thenAccept = 
          sleep(6);
          assertTrue(thenAccept.isDone());  
          verify(mocknotificationService, times(1)).notify(Mockito.anystring());
    }

通常情况下,您想要测试底层操作是否以预期的结果完成、具有预期的副作用,或者至少在不抛出异常的情况下完成。这可以很容易地实现

@Test
public void comletableFutureThenAccept() {
      CompletableFuture<Void> future = someMethod();
      future.join();
      /* check for class under test to have the desired state */
}

join() 将等待完成和 return 结果(在 Void 的情况下可以忽略),如果 future 异常完成则抛出异常。

如果在一定时间内完成实际上是测试的一部分,只需使用

@Test(timeout = 5000)
public void comletableFutureThenAccept() {
      CompletableFuture<Void> future = someMethod();
      future.join();
      /* check for class under test to have the desired state */
}

在不太可能的情况下,你真的只想在指定时间内测试完成,即不关心操作是否抛出异常,你可以使用

@Test(timeout = 5000)
public void comletableFutureThenAccept() {
      CompletableFuture<Void> future = someMethod();
      future.exceptionally(t -> null).join();
}

这会用 null 结果替换异常完成,因此,join() 不会抛出异常。所以只剩下超时了。

Java 9 允许另一种选择,不使用 JUnit 的超时。

@Test()
public void comletableFutureThenAccept() {
      CompletableFuture<Void> future = someMethod().orTimeout(5, TimeUnit.SECONDS);
      future.join();
      /* check for class under test to have the desired state */
}

这样做的好处是,如果操作及时完成但后续验证需要更长的时间,也不会失败。