java - 无法使用 mongodb react 测试功能端点

标签 java spring spring-test spring-webflux

我正在使用 Spring Data Reactive MongoDB 存储库来非阻塞地保存新的 pojo。我的路由器功能是:

//other routes
    .andRoute(POST("/article/json"), articleHandler::createArticle);

处理函数是:

public Mono<ServerResponse> createArticle(ServerRequest request) {
        Flux<Article> article = request.bodyToFlux(Article.class);
        articleRepository.insert(article).subscribe();
        return ServerResponse.ok().build();
    }

我的测试方法:

  @Test
        public void givenNewArticle_whenDataIsValid_thenSuccess() {
            //create new article object

            webTestClient.post()
                    .uri("/article/json")
                    .body(fromObject(article))
                    .exchange()
                    .expectStatus().isOk();
        }

如果我通过curl发送json数据,应用程序工作正常。但测试方法不行。并且日志中没有错误或任何插入文档事件:

2017-11-09 10:49:27.793  INFO 18224 --- [       Thread-4] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:6, serverValue:17563}] to 10.45.250.101:9017
2017-11-09 10:49:27.793  INFO 18224 --- [       Thread-5] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:5, serverValue:17562}] to 10.45.250.101:9017
2017-11-09 10:49:28.115  INFO 18224 --- [      Thread-11] .r.c.ReactiveWebServerApplicationContext : Closing org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext@4e423aa2: startup date [Thu Nov 09 10:49:23 MSK 2017]; root of context hierarchy
2017-11-09 10:49:28.117 DEBUG 18224 --- [      Thread-11] o.s.d.r.l.RedisMessageListenerContainer  : Stopped RedisMessageListenerContainer
2017-11-09 10:49:28.127  INFO 18224 --- [      Thread-11] org.mongodb.driver.connection            : Closed connection [connectionId{localValue:4, serverValue:17561}] to 10.45.250.101:9017 because the pool has been closed.
2017-11-09 10:49:28.128  INFO 18224 --- [      Thread-11] org.mongodb.driver.connection            : Closed connection [connectionId{localValue:3, serverValue:17560}] to 10.45.250.101:9017 because the pool has been closed.
2017-11-09 10:49:28.129  INFO 18224 --- [      Thread-11] org.mongodb.driver.connection            : Closed connection [connectionId{localValue:5, serverValue:17562}] to 10.45.250.101:9017 because the pool has been closed.
2017-11-09 10:49:28.129  INFO 18224 --- [      Thread-11] org.mongodb.driver.connection            : Closed connection [connectionId{localValue:6, serverValue:17563}] to 10.45.250.101:9017 because the pool has been closed.
2017-11-09 10:49:28.132  INFO 18224 --- [      Thread-11] r.ipc.netty.tcp.BlockingNettyContext     : Stopped HttpServer on /0:0:0:0:0:0:0:0:61441

通过 WebTestClient 测试 Restful api 的正确方法是什么? 蒂亚!

最佳答案

您的测试正在运行并暗示存在实际错误。

一般规则:您永远不应该在返回响应式类型的方法中调用subscribe您应该从头到尾构建一个响应式管道。

错误解释

在这种情况下,调用 subscribe 将触发保存操作,但不能保证该方法在完成后会返回。 subscribe 返回一个 Disposable,用于跟踪该操作的完成情况(成功或错误)。保存数据的实际工作可能发生在不同的线程中。

这在使用curl 手动完成时有效,因为从服务器返回响应后您的应用程序仍在运行。对于您的测试,应用程序会在保存操作发生之前停止。保存操作尚未发生。

您可以通过以下方式“修复”此问题:

public Mono<ServerResponse> createArticle(ServerRequest request) {
    Flux<Article> article = request.bodyToFlux(Article.class);
    articleRepository.insert(article).subscribe().block();
    return ServerResponse.ok().build();
}

但是通过此修复,您将在响应式(Reactive)管道中间引入阻塞操作 - 这是一个严重的性能问题。这样做可能会阻塞服务器的少数线程并导致性能非常差。

修复此错误

修复如下所示(分解超出所需的内容,您可以使其变得更短):

public Mono<ServerResponse> createArticle(ServerRequest request) {
    Flux<Article> articles = request.bodyToFlux(Article.class);
    Flux<Article> savedArticles = articleRepository.insert(articles);
    return savedArticles.then(ServerResponse.ok().build());
}

与之前的解决方案相比,此修复有两个优点:

  • 它是完全异步、非阻塞的,并且背压信息会传递到整个管道
  • 如果保存数据时发生错误,这将导致向客户端发出错误响应(您可以使用方便的 onError* Reactor 运算符自定义内容)

进入 react 性思维模式远非显而易见,因此编写测试绝对是挑战您的假设的正确方法 - 您做出了正确的决定。

关于java - 无法使用 mongodb react 测试功能端点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47187870/

相关文章:

java - 我们可以在 Java 的 Maven 构建过程中进行 bash 测试吗?

java - MVC Controller 方法中的 Spring BindingResult

java - 遗留代码的集成测试中如何处理事务

spring - WebMvcTest 太贪心了

java - 使用文件处理程序创建目录

java:创建一个方法来操作两个对象(初学者)

java - Hibernate 搜索 - '%like%' 类型查询

java - HSQL数据库偶尔会执行两次schema.sql

java - spring boot 如何使用 src/test/resource/中的 yaml 文件 Autowiring bean

java - 是一次性从数据库获取所有需要的数据更好,还是更频繁地发出请求更好?