如何通过避免手动睡眠来对 CompletableFuture.thenAccept() 进行单元测试
How to unit test CompletableFuture.thenAccept() by avoiding manual sleep
如何在单元测试中避免手动休眠。
假设在下面的代码中,Process
和 notify
需要大约 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 */
}
这样做的好处是,如果操作及时完成但后续验证需要更长的时间,也不会失败。
如何在单元测试中避免手动休眠。
假设在下面的代码中,Process
和 notify
需要大约 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 */
}
这样做的好处是,如果操作及时完成但后续验证需要更长的时间,也不会失败。