【问题标题】:Spring webflux, testing `ServerResponse`Spring webflux,测试`ServerResponse`
【发布时间】:2026-01-17 20:55:01
【问题描述】:

如何测试接收ServerRequest 并返回Mono<ServerResponse>处理程序 方法?

我可以通过org.springframework.mock.web.reactive.function.server.MockServerRequest.builder() 创建一个ServerRequest。并在ServerResponse.statusCode() 上声明。但是我想测试一下这个ServerResponse 的正文,但是没有办法提取它。

ServerResponse response = target.search(MockServerRequest.builder()
    .method(HttpMethod.GET)
    .build()
  ).block();

assertThat(response.statusCode()).isEqualTo(HttpStatus.OK);
//assertThat(response.body()).isNotNull();

我不想用WebTestClient 做更广泛的测试,我想用单元测试测试所有可能的响应情况。

谢谢

【问题讨论】:

    标签: spring unit-testing testing spring-webflux


    【解决方案1】:

    因此,似乎最好的解决方案是使用WebTestClient。然而,这个可以在没有运行服务器的情况下使用;

    spring-test 模块包含一个 WebTestClient,可用于测试 WebFlux 服务器端点有或没有正在运行的服务器

    -- https://docs.spring.io/spring/docs/5.0.0.BUILD-SNAPSHOT/spring-framework-reference/html/web-reactive.html#web-reactive-tests

    诀窍是使用bindTo..() 构建器方法。就我而言,bindToRouterFunction(new MyRouter(new MyHandler())) 效果很好

    【讨论】:

    • 我以为你提到你不想用WebTestClient做更广泛的测试
    • 你是对的。我关心的是在不启动整个服务器的情况下保持测试快速运行。而且,正如我在回答中解释的那样,WebTestClient 可以在没有正在运行的服务器的情况下使用。
    • 有没有办法在不使用WebTestClient 的情况下断言ServerResponse
    • 很抱歉,我不再积极使用 spring。所以我不能给你一个准确的答案。
    【解决方案2】:

    我有完全相同的问题,因为我不想为每个测试启动整个 Spring 上下文。感谢您在自己的答案中提供的信息,这对我有帮助。这是一个包含 Mockito 和 JUnit5 的完整示例:

    import java.util.Arrays;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.extension.ExtendWith;
    import org.mockito.Mock;
    import org.mockito.Mockito;
    import org.mockito.junit.jupiter.MockitoExtension;
    import org.springframework.http.MediaType;
    import org.springframework.test.web.reactive.server.WebTestClient;
    
    @ExtendWith(MockitoExtension.class)
    class UsersHandlerTest {
      @Mock
      UserRepository userRepository;
    
      WebTestClient client;
    
      @BeforeEach
      public void setUp() {
        UsersHandler usersHandler = new UsersHandler(userRepository);
        Router router = new Router(usersHandler);
    
        Mockito.when(userRepository.findAll()).thenReturn(
          Arrays.asList("", ""));
    
        client = WebTestClient.bindToRouterFunction(router.getUsers()).build();
      }
    
      @Test
      public void getCommands() {
        client.get().uri("/users")
          .accept(MediaType.APPLICATION_JSON_UTF8)
          .exchange()
          .expectStatus().isOk()
          .expectBody().json("{}");
      }
    }
    

    【讨论】:

      【解决方案3】:

      我已经要求similar question 坚持不使用 WebTestClient。 在发现可以将响应转换为允许检查主体(实体)的类型后,我最终回答了自己的问题。

      神奇的线(Kotlin)是:

      (serverResponse as EntityResponse<Fleet>).entity()
      

      编辑: 所以对于期待一个空的身体的情况,你可以这样做:

      assert(serverResponse !is EntityResponse<*>)
      

      感谢@andred 指出这一点

      【讨论】:

      • 小心使用这种方法:它只有在响应实体可用时才有效。如果 ServerResponse-Builder 用于构建 noContent- 或 notFound-Response,则它不起作用。在转换之前始终检查类型。
      • 你是对的。我有一个改变来重新讨论这个话题,所以在你不期望正文的情况下(比如在 noContent 中),你可以断言相反的assert(it !is EntityResponse&lt;*&gt;)
      最近更新 更多