【问题标题】:How to unit test CompletableFuture.thenAccept() by avoiding manual sleep如何通过避免手动睡眠来对 CompletableFuture.thenAccept() 进行单元测试
【发布时间】:2019-01-22 12:59:10
【问题描述】:

如何避免在单元测试中手动休眠。 假设在下面的代码中,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类中,这只是为了展示一些示例代码。要测试的方法在其他类中并注入我的Test类中。我想了解如何避免在单元测试中睡觉。作为我正在测试的系统(某些方法可能需要随机的时间)
  • 所示的测试不测试任何东西,除了该方法最终将完成(或在五秒的任意时间间隔内)。这个方法实际上应该测试什么?
  • 更新了代码..抱歉造成混乱

标签: java-8 completable-future


【解决方案1】:

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

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

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

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

@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 */
}

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

【讨论】:

  • 谢谢,是的,这就是我想要的。加入和 orTimeout 将解决我的问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多