【问题标题】:Is MockMvc eligible for WebFlux controllers testing?MockMvc 是否有资格进行 WebFlux 控制器测试?
【发布时间】: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"));
    }

第一个测试检查对于“晴天场景”,我们得到了我们期望的两个人。第二个测试检查发生异常时会发生什么。

当我一个一个地运行测试时,它们可以完美运行。但是当我同时运行它们时,有时它们通过,有时其中一个失败,有时两者都失败。失败原因不同:

  1. Jackson 有时会在 JSON 解析期间抱怨到达 EOF(“由于输入结束,没有要映射的内容”,尽管在日志中我可以看到有效的完整 JSON)
  2. 有时第一次测试失败,第二次通过,就好像在这两种情况下都返回了一个错误,尽管我可以在日志中看到第一次测试生成的是正常响应,而不是错误的响应
  3. 有时第二次测试失败,第一次通过,好像在这两种情况下都返回了有效的 JSON

所以看起来存在一些并发问题。但是我的测试代码很简单,没有用到任何并发相关的概念。

以下测试在我的机器上 100% 失败(它只是重复运行这 2 个测试 1000 次):

    @Test
    void manyTimes() throws Exception {
        for (int i = 0; i < 1000; i++) {
            streamsPersons();
            handlesExceptionDuringStreaming();
        }
    }

问题如下:

  1. MockMvc 可以用来测试反应式控制器吗?
  2. 如果可以,我是否做错了什么?

这里是完整的项目源代码:https://github.com/rpuch/sse-webflux-tests manyTests() 方法已被注释掉,必须重新启用才能使用。

【问题讨论】:

    标签: java concurrency spring-webflux mockmvc


    【解决方案1】:

    1. MockMvc 可以用来测试响应式控制器吗?

    答案是否定的,MockMvc 是一个阻塞的 mockClient,它会调用你的方法一次并返回。它无法在项目发出时连续读取项目您需要使用的客户端是 Spring WebClient

    您可以在此处阅读更多关于如何使用 Spring WebTestClient 处理 testing infinite streams 的信息。

    2。如果可以,我是否做错了什么?

    查看问题一的答案。

    【讨论】:

      猜你喜欢
      • 2013-06-06
      • 2016-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-20
      • 2021-01-20
      • 2014-05-31
      • 1970-01-01
      相关资源
      最近更新 更多