MockMvc 是否有资格进行 WebFlux 控制器测试?
Is MockMvc eligible for WebFlux controllers testing?
我有一个简单的 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"));
}
第一个测试检查 'sunny day scenario' 我们得到了我们期望的两个人。第二个测试检查发生异常时会发生什么。
当我 运行 一项一项地进行测试时,测试工作完美。但是当我 运行 他们两个时,有时他们通过,有时其中一个失败,有时两个都失败。失败原因不同:
- 有时 Jackson 在 JSON 解析期间抱怨已达到 EOF('No content to map due to end-of-input',尽管在日志中我可以看到有效的完整 JSON)
- 有时第一次测试失败而第二次通过,就好像在这两种情况下都返回了错误,即使我可以在日志中看到第一次测试生成了正常响应,而不是错误的响应
- 有时第二次测试失败,第一次通过,就好像在这两种情况下都有效 JSONs where returned
看起来好像存在一些并发问题。但是我的测试代码很简单,没有用到任何并发相关的概念。
以下测试在我的机器上 100% 次失败(只是 运行 这两个测试重复 1000 次):
@Test
void manyTimes() throws Exception {
for (int i = 0; i < 1000; i++) {
streamsPersons();
handlesExceptionDuringStreaming();
}
}
问题如下:
MockMvc
可以用来测试反应式控制器吗?
- 如果可以,我是不是做错了什么?
这里是完整的项目源代码:https://github.com/rpuch/sse-webflux-tests
manyTests()
方法被注释掉,必须重新启用才能使用。
1. MockMvc 是否可以用于测试反应式控制器?
答案是否定的,MockMvc 是一个阻塞的 mockClient,它将调用您的方法一次 return。它无法在项目发出时连续读取项目您需要使用的客户端是 Spring WebClient
.
您可以在此处阅读更多有关如何使用 Spring WebTestClient
.
testing infinite streams 的信息
2。如果可以,我是不是做错了什么?
查看问题一的答案。
我有一个简单的 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"));
}
第一个测试检查 'sunny day scenario' 我们得到了我们期望的两个人。第二个测试检查发生异常时会发生什么。
当我 运行 一项一项地进行测试时,测试工作完美。但是当我 运行 他们两个时,有时他们通过,有时其中一个失败,有时两个都失败。失败原因不同:
- 有时 Jackson 在 JSON 解析期间抱怨已达到 EOF('No content to map due to end-of-input',尽管在日志中我可以看到有效的完整 JSON)
- 有时第一次测试失败而第二次通过,就好像在这两种情况下都返回了错误,即使我可以在日志中看到第一次测试生成了正常响应,而不是错误的响应
- 有时第二次测试失败,第一次通过,就好像在这两种情况下都有效 JSONs where returned
看起来好像存在一些并发问题。但是我的测试代码很简单,没有用到任何并发相关的概念。
以下测试在我的机器上 100% 次失败(只是 运行 这两个测试重复 1000 次):
@Test
void manyTimes() throws Exception {
for (int i = 0; i < 1000; i++) {
streamsPersons();
handlesExceptionDuringStreaming();
}
}
问题如下:
MockMvc
可以用来测试反应式控制器吗?- 如果可以,我是不是做错了什么?
这里是完整的项目源代码:https://github.com/rpuch/sse-webflux-tests
manyTests()
方法被注释掉,必须重新启用才能使用。
1. MockMvc 是否可以用于测试反应式控制器?
答案是否定的,MockMvc 是一个阻塞的 mockClient,它将调用您的方法一次 return。它无法在项目发出时连续读取项目您需要使用的客户端是 Spring WebClient
.
您可以在此处阅读更多有关如何使用 Spring WebTestClient
.
2。如果可以,我是不是做错了什么?
查看问题一的答案。