【发布时间】:2019-08-25 20:20:33
【问题描述】:
我必须在 Completable Future 中超时运行函数。只有当原始方法花费的时间超过给定的超时时间时,才应该调用可运行函数。单位不断给= 需要但未调用:但是,与此模拟的交互恰好有 3 次。
我想要做的是,我正在尝试为方法执行添加超时 (getResponseWithTimeoutFunction(itemRequest)),如果该方法需要更多时间,则终止它并发布计数(以了解超时响应率)作为度量。
@Test
public void testTimeoutFunction() throws Exception {
Response response = getResponseForTest();
when(requestAdapter.transform(itemRequest)).thenReturn(Request);
when(dataProvider
.provide(any(Request.class)))
.thenAnswer((Answer<Response>) invocation -> {
Thread.sleep(1000000);
return response;
});
processor = spy(getProcessor());
when(itemRequest.getRequestContext()).thenReturn(itemRequestContext);
when(itemRequestContext.getMetadata()).thenReturn(requestContextMetadata);
List<Item> output = processor.getItemist(ITEM_ID, itemRequest);
assertTrue(output.isEmpty());
verify(processor, times(1)).processRequest(Request);
verify(processor, times(1)).responseTimedOutCount();
}
这是我正在测试的方法:
public class Process {
@VisibleForTesting
void responseTimedOutCount() {
//log metrics
}
private CompletableFuture<Response> getResponseAsync(final ScheduledExecutorService delayer,
final ItemRequest itemRequest) {
return timeoutWithTimeoutFunction(delayer, EXECUTION_TIMEOUT, TimeUnit.MILLISECONDS,
CompletableFuture.supplyAsync(() -> getResponseWithTimeoutFunction(itemRequest), executorService),
Response.emptyResponse(), () -> responseTimedOutCount());
}
private Response getResponseWithTimeoutFunction(final ItemRequest itemRequest) {
//do something and return response
}
public List<Item> getItemList(final String id, final ItemRequest itemRequest) throws Exception {
final ScheduledExecutorService delayer = Executors.newScheduledThreadPool(1);
Response response;
if(validateItemId(id){
try {
response = getResponseAsync(delayer, itemRequest).get();
} catch (final Throwable t) {
response = Response.emptyResponse();
} finally {
delayer.shutdown();
}
return transform(response, id).getItems();
} else {
return null;
}
}
}
而超时功能使用=
public static <T> CompletableFuture<T> timeoutWithTimeoutFunction(final ScheduledExecutorService es,
final long timeout,
final TimeUnit unit,
final CompletableFuture<T> f,
final T defaultValue,
final Runnable r) {
final Runnable timeoutFunction = () -> {
boolean timedOut = f.complete(defaultValue);
if (timedOut && r != null) {
r.run();
}
};
es.schedule(timeoutFunction, timeout, unit);
return f;
}
来自 Junit 的异常:
Wanted but not invoked: process.responseTimedOutCount(); -> at processTest.testTimeoutFunction(processTest.java:377)
However, there were exactly 3 interactions with this mock:
process.getItemList( ITEM_ID, itemRequest ); -> at processTest.testTimeoutFunction(processTest.java:373)
process.validateItemId( ITEM_ID ); -> at process.getItemList(process.java:133)
process.processRequest( request ); -> at process.getResponseWithTimeoutFunction(process.java:170)
【问题讨论】:
-
Thread.sleep 在测试中总是一个不好的迹象。您如何确定时间完全符合预期?
-
这就是问题所在。我想测试我的超时功能是否按预期正确使用。
-
如果希望您不介意我的提问:为什么要在此处使用单独的
ScheduledExecutorService来处理超时处理,而您可以简单地在CompletableFuture上使用get(timeout, TimeUnit)代替?我能看到的唯一原因是responseTimedOutCount不应该在main线程上运行。 -
@second 很抱歉没有意识到这一点。你能简单地告诉我吗?
-
我已经读过这个
tutorial,它使用延迟器使代码非阻塞,但是在这种情况下,在你知道isDone() == true之前你不能真正使用get方法。
标签: java junit java-8 mockito completable-future