【问题标题】:Springboot test controller via WebClient instead of WebTestClientSpringboot 测试控制器通过 WebClient 而不是 WebTestClient
【发布时间】:2021-10-30 03:45:15
【问题描述】:

我正在尝试一些可能被误导的事情,但请帮忙。

我想通过@WebFluxTest 测试springboot 控制器。但是我想使用WebClient 而不是WebTestClient。如何做到这一点?

到目前为止,我设法使用反射从 WebTestClient 中获取 ExchangeFunction 并将其分配给 WebClient - 它有效!拨打电话,控制器响应 - 太棒了。但是我认为这不是一个好方法。有没有更好的办法?

谢谢。

【问题讨论】:

  • 为什么不想使用专为测试而设计的WebTestClient
  • 长话短说:我们在内部构建并包含客户服务。客户端也应该被测试。集成测试目前不是一种选择(管道不允许这样做)。 P.S:我们曾经使用DropWizard框架,上面的场景很容易用2行代码完成。
  • 使用WebClient.Builder创建一个并使用spring boot的自动配置。我仍然不明白为什么你想做的事情不能用 WebTestClient 完成,它只是 WebClient 的包装。
  • @M. Deinum,你介意举个例子吗。我是 Spring 和 Springboot 的新手。目前正在将服务从 Dropwizard 迁移到 Springboot。
  • P.S:我很乐意私下进一步讨论这个问题。如果您的好奇心占上风,请告诉我。

标签: spring spring-boot unit-testing spring-webclient


【解决方案1】:

理想情况下,您应该使用WebTestClient,它更像是WebClient 的方便包装。就像TestRestTemplate 用于RestTemplate。两者都允许创建请求,并且您可以轻松地做出断言。它们的存在是为了让您的测试生活更轻松。

如果您真的想使用WebClient 而不是WebTestClient 并手动执行断言(这意味着您可能会使事情复杂化),您可以使用WebClient.Builder 创建一个。 Spring Boot 会自动配置一个,您可以简单地在测试中自动装配它并调用build 方法。

@SpringBootTest
public void YourTest {
  
  @Autowired
  private WebClient.Builder webClientBuilder;

  @Test
  public void doTest() {
    WebClient webClient = webClientBuilder.build();
  }
}

@WebFluxTest 也应如此。

【讨论】:

  • 使用 @WebFluxTest(controllers = MyController.class) 我遇到问题:Unsatisfied dependency expressed through field 'webClientBuilder'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.web.reactive.function.client.WebClient$Builder
  • 我也想知道 WebTestClient 真的使用 WebClient 吗? WebTestClient 看起来与 WebClient 非常相似,但所有接口都不同。为了方便起见,似乎已复制代码并添加了断言。
  • 没有复制任何内容,它委托给 WebClient 并添加断言。您可以为自动配置添加@Import(WebClientAutoConfiguration),我错误地认为这是@WebFluxTest 的一部分。
  • 仍在尝试访问80端口:org.springframework.web.reactive.function.client.WebClientRequestException: Connection refused: no further information: /127.0.0.1:80; nested exception is io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /127.0.0.1:80 at org.springframework.web.reactive.function.client.ExchangeFunctions$DefaultExchangeFunction.lambda$wrapException$9(ExchangeFunctions.java:141) Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: Error has been observed at the following site(s):
  • Spring 版本:5.3.9 & Springboot 版本:2.5.3
【解决方案2】:

好的,经过大量实验,这里有一个通过模拟连接测试 springboot 控制器和过滤器的解决方案 - 没有 web 服务,没有端口和快速测试。

不幸的是,我没有弄清楚如何通过@WebFluxTestWebClient 进行操作,而是可以使用MockMvc 来达到预期的效果:

@ExtendWith(SpringExtension.class)
@Import({SomeDependencyService.class, SomeFilter.class})
@WebMvcTest(controllers = SomeController.class, excludeAutoConfiguration = SecurityAutoConfiguration.class)
@AutoConfigureMockMvc()
public class SomeControllerTest {
    @MockBean
    private SomeDependencyService someDependencyService;

    @Autowired
    private MockMvc mockMvc;

    private SomeCustomizedClient subject;

    @BeforeEach
    public void setUp() {
        subject = buildClient();

        WebClient webClient = mockClientConnection();
        subject.setWebClient(webClient);
    }

    private WebClient mockClientConnection() {
        MockMvcHttpConnector mockMvcHttpConnector = new MockMvcHttpConnector(mockMvc);
        WebClient webClient = WebClient.builder().clientConnector(mockMvcHttpConnector).build();
        return webClient;
    }

    @Test
    public void sample() {
        when(SomeDependencyService.somePersistentOperation(any(), any())).thenReturn(new someDummyData());

        SomeDeserializedObject actual = subject.someCallToControllerEndpoint("example param");

        assertThat(actual.getData).isEquals("expected data");
    }

}

现在可以测试您的自定义客户端(例如,如果您有内部 java 客户端,其中包含一些重要的自定义,如安全性、etags、日志记录、反序列化和统一错误处理)和关联的控制器(如果您@ 987654325@他们一起)以单元测试为代价。

您不必启动整个服务来验证客户端和控制器是否正常工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-08
    • 2017-12-06
    • 2021-06-01
    • 2021-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多