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

Nir*_*ane 1 java-8 completable-future

如何避免单元测试中的手动睡眠。假设在下面的代码中,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);
    }

}
Run Code Online (Sandbox Code Playgroud)

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

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

Hol*_*ger 5

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

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

join()将等待完成并返回结果(在 的情况下您可以忽略Void),如果未来异常完成则抛出异常。

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

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

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

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

这用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 */
}
Run Code Online (Sandbox Code Playgroud)

如果操作及时完成但后续验证需要更长的时间,这具有不会失败的优点。