【发布时间】:2019-12-29 02:32:16
【问题描述】:
我有一个简单的 WebFlux 应用程序(使用控制器,而不是路由器功能)。唯一不标准的部分是它使用了 Server-Sent-Events。
控制器的一个有趣的部分是
@GetMapping(path = "/persons", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<Object>> persons() {
return service.persons()
.map(this::personToSse)
.onErrorResume(e -> Mono.just(throwableToSse(e)));
}
private ServerSentEvent<Object> personToSse(Person person) {
return ServerSentEvent.builder().data(person).build();
}
服务:
public interface Service {
Flux<Person> persons();
}
我有两个测试:
@SpringBootTest(classes = Config.class)
@AutoConfigureMockMvc
class PersonsControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private Service service;
@Test
void streamsPersons() throws Exception {
when(service.persons())
.thenReturn(Flux.just(new Person("John", "Smith"), new Person("Jane", "Doe")));
String responseText = mockMvc.perform(get("/persons").accept(MediaType.TEXT_EVENT_STREAM))
.andExpect(status().is2xxSuccessful())
.andExpect(content().string(not(isEmptyString())))
.andReturn()
.getResponse()
.getContentAsString();
assertThatJohnAndJaneAreReturned(responseText);
}
@Test
void handlesExceptionDuringStreaming() throws Exception {
when(service.persons())
.thenReturn(Flux.error(new RuntimeException("Oops!")));
String responseText = mockMvc.perform(get("/persons").accept(MediaType.TEXT_EVENT_STREAM))
.andExpect(status().is2xxSuccessful())
.andReturn()
.getResponse()
.getContentAsString();
assertThat(responseText, is("event:internal-error\ndata:Oops!\n\n"));
}
第一个测试检查对于“晴天场景”,我们得到了我们期望的两个人。第二个测试检查发生异常时会发生什么。
当我一个一个地运行测试时,它们可以完美运行。但是当我同时运行它们时,有时它们通过,有时其中一个失败,有时两者都失败。失败原因不同:
- Jackson 有时会在 JSON 解析期间抱怨到达 EOF(“由于输入结束,没有要映射的内容”,尽管在日志中我可以看到有效的完整 JSON)
- 有时第一次测试失败,第二次通过,就好像在这两种情况下都返回了一个错误,尽管我可以在日志中看到第一次测试生成的是正常响应,而不是错误的响应
- 有时第二次测试失败,第一次通过,好像在这两种情况下都返回了有效的 JSON
所以看起来存在一些并发问题。但是我的测试代码很简单,没有用到任何并发相关的概念。
以下测试在我的机器上 100% 失败(它只是重复运行这 2 个测试 1000 次):
@Test
void manyTimes() throws Exception {
for (int i = 0; i < 1000; i++) {
streamsPersons();
handlesExceptionDuringStreaming();
}
}
问题如下:
-
MockMvc可以用来测试反应式控制器吗? - 如果可以,我是否做错了什么?
这里是完整的项目源代码:https://github.com/rpuch/sse-webflux-tests
manyTests() 方法已被注释掉,必须重新启用才能使用。
【问题讨论】:
标签: java concurrency spring-webflux mockmvc