java - Spring Boot2 功能端点 WebFluxTest 与 PUT-with-ID 和 DELETE-for-id ({id}) URL 不匹配

标签 java spring spring-boot spring-webflux spring-boot-test

我正在开发一个 Spring boot2 应用程序,该应用程序是使用功能端点开发的。路由器附加了一些过滤器( HandlerFilterFunction<ServerResponse, ServerResponse> 的实现)。我正在尝试测试我遇到困难的过滤器并提出这个问题。

使用的框架

  • Spring Boot 2.0.0.RELEASE
  • 测试NG

我正在尝试测试的过滤器

public class ResourceParsingFilter implements HandlerFilterFunction<ServerResponse, ServerResponse> {

    /**
     * {@inheritDoc}
     */
    @Override
    public Mono<ServerResponse> filter(ServerRequest request, HandlerFunction<ServerResponse> next) {
        final HttpMethod httpMethod = request.method();
        final String requestPath = request.path();

        // Collect the resource id and type from path
        final ResourceDetail resourceDetail = WebUtilsFunctions.FN_GET_RESOURCE_DETAIL_FROM_PATH.apply(requestPath);

        switch (httpMethod) {
        case GET:
            if (!request.queryParam("q").isPresent() && StringUtils.isBlank(resourceDetail.getResourceId())) {
                return Mono.error(
                        new AppException(Exceptions.APP_400002.exceptionCode(), 
                                WebUtilsFunctions.FN_FORMAT_STRING.apply(Exceptions.APP_400002.exceptionMessage(), new String[] {httpMethod.name()})));
            }
            break;
        case PUT:
        case DELETE:
            if (StringUtils.isBlank(resourceDetail.getResourceId())) {
                return Mono.error(
                        new AppException(Exceptions.APP_400002.exceptionCode(), 
                                WebUtilsFunctions.FN_FORMAT_STRING.apply(Exceptions.APP_400002.exceptionMessage(), new String[] {httpMethod.name()})));
            }
            break;
        default:
            break;
        }

        // Store resourceDetail in request
        request.attributes().put("RESOURCE_DETAIL", resourceDetail);

        return next.handle(request);
    }

}

模拟应用配置来测试过滤器

@Configuration
@EnableWebFlux
public class MockAppConfig {
    @Bean
    public ResourceParsingFilter resourceParsingFilterBean() {
        return new ResourceParsingFilter();
    }

    @Bean // This is my own custom exception handler implementation
    public GlobalExceptionHandler globalExceptionHandler(final ApplicationContext applicationContext,
            final ServerCodecConfigurer serverCodecConfigurer) {
        return new GlobalExceptionHandler(applicationContext, serverCodecConfigurer);
    }
}

模拟路由器配置(我根据 Spring Boot 团队在他们的 gitter channel ( https://github.com/spring-projects/spring-boot/issues/6602 ) 中的建议单独创建了这个类

@Configuration
public class MockResourceParsingRouterConfig {
    @Autowired
    private ResourceParsingFilter resourceParsingFilter;

    @Bean("resourceParsingFilterRoutes")
    public RouterFunction<ServerResponse> resourceParsingFilterRoutes() {
        // Dummy route configuration for testing ResourceParsingFilter
        return RouterFunctions.route(RequestPredicates.GET("/resourceParsing/{id}"), req -> ServerResponse.ok().build())
                .andRoute(RequestPredicates.PUT("/resourceParsing/{id}"), req -> ServerResponse.ok().build())
                .andRoute(RequestPredicates.DELETE("/resourceParsing/{id}"), req -> ServerResponse.ok().build())
                .andRoute(RequestPredicates.GET("/resourceParsing/"), req -> ServerResponse.ok().build()) // GET Search URL
                .filter(resourceParsingFilter);
    }
}

测试类

@Test(groups = "resourceParsingFilterTests")
@WebFluxTest
@Import({MockAppConfig.class, MockResourceParsingRouterConfig.class})
public class ResourceParsingFilterTest extends AbstractTestNGSpringContextTests {

    @Autowired
    private WebTestClient webTestClient;

//  ====== Passing tests
    @Test
    public void get_withoutId() {
        webTestClient.get().uri("/resourceParsing/")
            .exchange() // Fire http request
            .expectStatus() // Assert on HTTP Status
            .isBadRequest()
            ;
    }

    @Test(dependsOnMethods = {"get_withoutId"})
    public void get_withoutId_searchQueryParamPresent() {
        webTestClient.get().uri("/resourceParsing/?q=id:345")
            .exchange() // Fire http request
            .expectStatus() // Assert on HTTP Status
            .isOk()
            ;
    }

    // ====== Failing tests
    @Test(dependsOnMethods = {"get_withoutId_searchQueryParamPresent"})
    public void put_withoutId() {
        webTestClient.put().uri("/resourceParsing/")
            .exchange() // Fire http request
            .expectStatus() // Assert on HTTP Status
            .isBadRequest()
            ;
    }
}

Th测试put_withoutId失败,因为(模拟)服务器抛出 404而不是预期的400 .

请检查 GitHub 存储库 https://github.com/nnanda2016/router-fn-demo完整的代码(如果您愿意),这是一个与我的真实应用程序同一行的演示应用程序(由于客户保密合规性,我无法共享真实代码)。

有人可以给我一些如何解决这个问题的指导吗?

最佳答案

@WebFluxTest注解不支持 RouterFunction 的测试,但仅限 WebFlux 带注释的 Controller 。

@WebFluxTest@WebMvcTest是关于在没有完整 Web 基础设施的情况下将单个带注释的 Controller 作为 Web 组件进行测试。 RouterFunction通常依赖多个处理程序来定义实际函数 - 因此,如果没有对路由进行严格假设或要求开发人员设计其架构以具有多个RouterFunction,我们就无法一致地测试单个处理程序。 bean 类。

这将得到更好的记录 once this Spring Boot issue is resolved .

与此同时,您可能应该使用@SpringBootTest为了那个原因;如果您不要求特定端口,此集成将配置完整的 Web 堆栈,但不会启动任何服务器。

关于java - Spring Boot2 功能端点 WebFluxTest 与 PUT-with-ID 和 DELETE-for-id ({id}) URL 不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49355283/

相关文章:

java - 将两个不同选择的结果合并为一个结果集

Java 拖放

java有界泛型类型定义

java - Spring @CondiitonalOnProperty,只有缺失时如何匹配

spring-boot - spring boot - docker - Logback - 非root用户 - 权限被拒绝错误

java - 使用最新(2.10.0 到 3.1.0)Java DocuSignAPI 的 ClientHandlerException

java - MySql utf8不保存印地语和其他语言

java - 不能使用具有不同Spring Boot版本的库

java - 带有 Docker : environment variable to override RabbitMQ host IP property in spring boot's application. 属性的 Spring Boot 不工作

java - Protocol Buffer - @ModelAttribute