我一直在寻找关于如何最好地测试springmvc控制器方法的提示。我提出了一个非常简短的解决方案,但是有一个针对异步线程行为进行测试的试错解决方案。以下是示例代码,仅用于演示概念,可能有一两个输入错误:
控制器类:
@Autowired
Publisher<MyResponse> responsePublisher;
@RequestMapping("/mypath")
public SseEmitter index() throws IOException {
SseEmitter emitter = new SseEmitter();
Observable<MyResponse> responseObservable = RxReactiveStreams.toObservable(responsePublisher);
responseObservable.subscribe(
response -> {
try {
emitter.send(response);
} catch (IOException ex) {
emitter.completeWithError(ex);
}
},
error -> {
emitter.completeWithError(error);
},
emitter::complete
);
return emitter;
}
测试等级:
//A threaded dummy publisher to demonstrate async properties.
//Sends 2 responses with a 250ms pause in between.
protected static class MockPublisher implements Publisher<MyResponse> {
@Override
public void subscribe(Subscriber<? super MyResponse> subscriber) {
new Thread() {
@Override
public void run() {
try {
subscriber.onNext(response1);
Thread.sleep(250);
subscriber.onNext(response2);
} catch (InterruptedException ex) {
}
subscriber.onComplete();
}
}.start();
}
}
//Assume @Configuration that autowires the above mock publisher in the controller.
//Tests the output of the controller method.
@Test
public void testSseEmitter() throws Exception {
String path = "http://localhost/mypath/";
String expectedContent = "data:" + response1.toString() + "\n\n" +
"data:" + response2.toString() + "\n\n");
//Trial-and-Error attempts at testing this SseEmitter mechanism have yielded the following:
//- Returning an SseEmitter triggers 'asyncStarted'
//- Calling 'asyncResult' forces the test to wait for the process to complete
//- However, there is no actual 'asyncResult' to test. Instead, the content is checked for the published data.
mockMvc.perform(get(path).contentType(MediaType.ALL))
.andExpect(status().isOk())
.andExpect(request().asyncStarted())
.andExpect(request().asyncResult(nullValue()))
.andExpect(header().string("Content-Type", "text/event-stream"))
.andExpect(content().string(expectedContent))
}
如注解中所述,调用asyncresult()是为了确保发布者在测试完成之前完成其工作并发送这两个响应。如果没有它,内容检查将失败,因为内容中只存在一个响应。但是,没有要检查的实际结果,因此asyncresult为空。
我的具体问题是,是否有更好、更精确的方法来强制测试等待异步进程完成,而不是这里的klugie方法等待不存在的异步结果。我更广泛的问题是,与这些异步函数相比,是否有其他libs或spring方法更适合于此。谢谢!
1条答案
按热度按时间busg9geu1#
这是一个更一般的答案,因为它是为了测试一个sseemitter,它将永远运行,但将在给定的超时后从sse流断开连接。
至于一种不同于mvc的方法,正如@erindrummond对op评论的那样,您可能需要研究webflux。
这是一个极小的例子。您可能希望使用请求头、不同的匹配器或单独处理流输出进行扩展。
它正在设置一个从sse流断开连接的延迟线程,这将允许执行Assert。