【问题标题】:Integration testing with Testcontainers + Quarkus + MongoDB使用 Testcontainers + Quarkus + MongoDB 进行集成测试
【发布时间】:2020-08-10 07:43:13
【问题描述】:

尝试使用测试容器进行集成测试。我正在测试休息 api 端点。这是技术堆栈 - quarkus、RESTEasy 和 mongodb-client

我可以看到 MongoDB 容器已成功启动,但出现异常。异常:“com.mongodb.MongoSocketOpenException:异常打开套接字”

2020-04-26 15:13:18,330 INFO  [org.tes.doc.DockerClientProviderStrategy] (main) Loaded org.testcontainers.dockerclient.UnixSocketClientProviderStrategy from ~/.testcontainers.properties, will try it first
2020-04-26 15:13:19,109 INFO  [org.tes.doc.UnixSocketClientProviderStrategy] (main) Accessing docker with local Unix socket
2020-04-26 15:13:19,109 INFO  [org.tes.doc.DockerClientProviderStrategy] (main) Found Docker environment with local Unix socket (unix:///var/run/docker.sock)
2020-04-26 15:13:19,258 INFO  [org.tes.DockerClientFactory] (main) Docker host IP address is localhost
2020-04-26 15:13:19,305 INFO  [org.tes.DockerClientFactory] (main) Connected to docker: 
  Server Version: 19.03.8
  API Version: 1.40
  Operating System: Docker Desktop
  Total Memory: 3940 MB
2020-04-26 15:13:19,524 INFO  [org.tes.uti.RegistryAuthLocator] (main) Credential helper/store (docker-credential-desktop) does not have credentials for quay.io
2020-04-26 15:13:20,106 INFO  [org.tes.DockerClientFactory] (main) Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
2020-04-26 15:13:20,107 INFO  [org.tes.DockerClientFactory] (main) Checking the system...
2020-04-26 15:13:20,107 INFO  [org.tes.DockerClientFactory] (main) ✔︎ Docker server version should be at least 1.6.0
2020-04-26 15:13:20,230 INFO  [org.tes.DockerClientFactory] (main) ✔︎ Docker environment should have more than 2GB free disk space
2020-04-26 15:13:20,291 INFO  [???? .2]] (main) Creating container for image: mongo:4.2
2020-04-26 15:13:20,420 INFO  [???? .2]] (main) Starting container with ID: d8d142bcdef8e2ebe9c09f171845deffcda503d47aa4893cd44e72d7067f0cdd
2020-04-26 15:13:20,756 INFO  [???? .2]] (main) Container mongo:4.2 is starting: d8d142bcdef8e2ebe9c09f171845deffcda503d47aa4893cd44e72d7067f0cdd
2020-04-26 15:13:22,035 INFO  [???? .2]] (main) Container mongo:4.2 started in PT3.721S
2020-04-26 15:13:24,390 INFO  [org.mon.dri.cluster] (main) Cluster created with settings {hosts=[127.0.0.1:27017], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500}
2020-04-26 15:13:24,453 INFO  [org.mon.dri.cluster] (main) Cluster created with settings {hosts=[127.0.0.1:27017], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500}
2020-04-26 15:13:24,453 INFO  [org.mon.dri.cluster] (cluster-ClusterId{value='5ea5dd542fb66c613dc74629', description='null'}-127.0.0.1:27017) Exception in monitor thread while connecting to server 127.0.0.1:27017: com.mongodb.MongoSocketOpenException: Exception opening socket
    at com.mongodb.internal.connection.SocketChannelStream.open(SocketChannelStream.java:63)
    at com.mongodb.internal.connection.InternalStreamConnection.open(InternalStreamConnection.java:126)
    at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:117)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.net.ConnectException: Connection refused
    at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
    at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:714)
    at sun.nio.ch.SocketAdaptor.connect(SocketAdaptor.java:122)
    at com.mongodb.internal.connection.SocketStreamHelper.initialize(SocketStreamHelper.java:64)
    at com.mongodb.internal.connection.SocketChannelStream.initializeSocketChannel(SocketChannelStream.java:72)
    at com.mongodb.internal.connection.SocketChannelStream.open(SocketChannelStream.java:60)
    ... 3 more

如果我使用 docker run,那么我的测试用例可以正常工作。

docker run -p 27017:27017 --name mongodb mongo:4.2

使用提到的测试容器@https://www.testcontainers.org/quickstart/junit_5_quickstart/

@Container
    static GenericContainer mongodb = new GenericContainer<>("mongo:4.2").withExposedPorts(27017);

【问题讨论】:

    标签: mongodb docker quarkus testcontainers


    【解决方案1】:

    如果没有看到您的测试配置,我不能肯定地说,但我猜它适用于 docker run 而不是 Testcontainers,因为 docker run 公开一个固定端口(始终为 27017)但 Testcontainers 将公开端口 @987654323 @作为随机端口(避免测试机器上的端口冲突)。

    要将 Testcontainers 与 Quarkus 测试一起使用,您的测试必须遵循以下流程:

    1. 启动容器。这是必要的,因为 MongoDB 的随机暴露端口只有在容器启动后才能知道。
    2. 在容器启动后从 Testcontainers 获取随机端口,然后设置依赖于容器端口的任何测试配置属性。例如:

      static GenericContainer mongodb = new GenericContainer<>("mongo:4.2").withExposedPorts(27017);
      static {
        mongodb.start();
        System.setProperty("quarkus.mongodb.connection-string",
                           "mongodb://" + mongodb.getContainerIpAddress() + ":" + mongodb.getFirstMappedPort());
      }
      
    3. 让 Quarkus 启动。由于 Quarkus 不支持动态配置,因此必须在 Quarkus 启动前设置 MongoDB 端口。

    【讨论】:

      【解决方案2】:

      从2.0.0.Alpha1 版本开始,如果未提供 Mongo 配置,Quarkus 将在开发和测试模式下通过测试容器自动启动 MongoDB。

      更多信息请参见this

      【讨论】:

        【解决方案3】:

        此解决方案有效,但 Quakus 提供了一种更简洁的方式来执行此检查 documentation。只需创建一个实现QuarkusTestResourceLifecycleManager的类

            public static class Initializer implements QuarkusTestResourceLifecycleManager {
        
                @Override
                public Map<String, String> start() {
                    mongodb.start();
                    return Maps.of("quarkus.mongodb.connection-string", "mongodb://" + mongodb.getContainerIpAddress() + ":" + mongodb.getFirstMappedPort());
                }
        
        
                @Override
                public void stop() {
                    mongodb.stop();
                }
            }
        
        

        然后用 @QuarkusTestResource(MyTestClass.Initializer.class)

        【讨论】:

          【解决方案4】:

          用示例扩展@juan-rada 答案(Quarkus + Mongo + Junit5)

          
          import java.util.Map;
          import org.apache.groovy.util.Maps;
          import org.junit.jupiter.api.Test;
          import org.testcontainers.containers.MongoDBContainer;
          import org.testcontainers.junit.jupiter.Container;
          import org.testcontainers.junit.jupiter.Testcontainers;
          import org.testcontainers.utility.DockerImageName;
          import io.quarkus.test.common.QuarkusTestResource;
          import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
          import io.quarkus.test.junit.QuarkusTest;
          
          @QuarkusTest
          @Testcontainers
          @QuarkusTestResource(FooIT.Initializer.class)
          public class FooIT {
          
              public static class Initializer implements QuarkusTestResourceLifecycleManager {
                  @Override
                  public Map<String, String> start() {
                      FooIT.mongoDBContainer.start();
                      // the way to dynamically expose allocated port
                      return Maps.of("quarkus.mongodb.connection-string", "mongodb://" + mongoDBContainer.getContainerIpAddress() + ":" + mongoDBContainer.getFirstMappedPort() + "/foo");
                  }
          
                  @Override
                  public void stop() {
                      FooIT.mongoDBContainer.stop();
                  }
              }
          
          
              @Container
              public static final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:latest"));
          
              @Test
              public void testFoo() {
                 ...
              }
          
          }
          

          【讨论】:

            猜你喜欢
            • 2017-12-19
            • 2022-10-21
            • 1970-01-01
            • 2019-09-06
            • 2021-05-02
            • 2019-08-18
            • 2019-09-19
            • 2021-05-11
            • 2020-04-02
            相关资源
            最近更新 更多