简体   繁体   English

MockMvc是否有资格进行WebFlux控制器测试?

[英]Is MockMvc eligible for WebFlux controllers testing?

I have a simple WebFlux application (that uses controllers, not router functions). 我有一个简单的WebFlux应用程序(使用控制器,而不是路由器功能)。 The only non-standard part is that it uses Server-Sent-Events. 唯一的非标准部分是它使用服务器发送事件。

An interesting part of the controller is 控制器的一个有趣的部分是

    @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();
    }

Service: 服务:

public interface Service {
    Flux<Person> persons();
}

I have two tests: 我有两个测试:

@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"));
    }

First test checks that for the 'sunny day scenario' we get two persons that we expect. 第一个测试检查在“晴天情况”下我们得到了我们期望的两个人。 Second test checks what happens when an exception occurs. 第二项测试检查发生异常时发生的情况。

The tests work perfectly when I run them one by one. 当我一个接一个地运行测试时,这些测试可以完美地工作。 But when I run them both, sometimes they pass, sometimes one of them fail, sometimes both fail. 但是当我同时运行它们时,有时它们会通过,有时其中一个会失败,有时都会失败。 Failure reasons are different: 失败原因不同:

  1. Sometimes Jackson complains during JSON parsing that an EOF was reached ('No content to map due to end-of-input', although in the log I can see a valid full JSON) 有时Jackson会在JSON解析过程中抱怨到达了EOF(“由于输入结束,无法映射任何内容”,尽管在日志中我可以看到有效的完整JSON)
  2. Sometimes first test fails and second passes as if in both cases an error was returned, even though I can see in the logs that for the first test normal response was generated, not the erroneous one 有时,第一次测试失败,第二次通过,好像两种情况都返回了错误,即使我在日志中看到为第一次测试生成的是正常响应,而不是错误的响应
  3. Sometimes second test fails and first passes as if in both cases valid JSONs where returned 有时第二次测试失败,并且第一次通过,好像在两种情况下都返回了有效的JSON

So it looks like there is some concurrency problem. 因此,似乎存在一些并发问题。 But my test code is simple enough, it does not use any concurrency-related concepts. 但是我的测试代码非常简单,没有使用任何与并发相关的概念。

The following test fails 100% of times on my machine (it just runs these 2 tests repeatedly 1000 times): 以下测试在我的计算机上100%失败(它仅将这2个测试重复运行1000次):

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

The questions follow: 问题如下:

  1. Can MockMvc be used to test reactive controllers at all? MockMvc可以用于测试无功控制器吗?
  2. If it can, do I do anything incorrectly? 如果可以,我做错了什么吗?

Here is the full project source code: https://github.com/rpuch/sse-webflux-tests The manyTests() method is commented out and has to be re-enabled to be used. 这是完整的项目源代码: https : manyTests()方法已被注释掉,必须重新启用才能使用。

1. Can MockMvc be used to test reactive controllers at all? 1. MockMvc可以用于测试无功控制器吗?

The answer is no, MockMvc is a blocking mockClient that will call your method once and return. 答案是否定的,MockMvc是一个阻塞的模拟客户端,它将调用您的方法一次并返回。 It does not have the ability to read items consecutively as they get emitted The client you need to use is the Spring WebClient . 它没有连续读取项目的功能,您需要使用的客户端是Spring WebClient

You can read more here how to go about testing infinite streams using the Spring WebTestClient . 您可以在此处了解更多有关如何使用Spring WebTestClient 测试无限流WebTestClient

2. If it can, do I do anything incorrectly? 2.如果可以,我做错了什么吗?

See the answer to question one. 请参阅问题一的答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM