docker 使用Testcontainers + Quarkus + MongoDB进行集成测试

k97glaaz  于 2023-01-16  发布在  Docker
关注(0)|答案(5)|浏览(174)

尝试集成测试的testcontainer。我正在测试API端点。这里是技术栈- quarkus,RESTEasy和mongodb-client
我可以看到MongoDB容器已成功启动,但出现异常。异常:“服务器异常:打开套接字”“时出现异常

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);
mwkjh3gx

mwkjh3gx1#

在没有看到您的测试配置之前,我不能确定,但我猜测它适用于docker run,而不是Testcontainers,因为docker run公开了一个固定端口(总是27017),但Testcontainers将端口27017 * 公开为随机端口 *(以避免测试机器上的端口冲突)。
要将Testcontainers与Quarkus测试一起使用,您的测试必须遵循以下流程:
1.启动容器。这是必要的,因为MongoDB的随机暴露端口只有在容器启动后才能知道。
1.启动容器后,从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());
}

1.让Quarkus启动。由于Quarkus不支持动态配置,您必须在Quarkus启动前设置MongoDB端口。

avwztpqn

avwztpqn2#

从版本2.0.0.Alpha1开始,如果没有提供Mongo配置,Quarkus将通过测试容器在开发和测试模式下自动启动MongoDB。
有关详细信息,请参阅此

fhity93d

fhity93d3#

这个解决方案是可行的,但是Quakus提供了一种更干净的方法来完成这个检查文档。

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)注解测试

yyyllmsg

yyyllmsg4#

通过示例(Quarkus + Mongo + Junit 5)扩展@juan-rada答案

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() {
       ...
    }

}
q43xntqr

q43xntqr5#

您可以在测试中使用@QuarkusTestResource(MongoDBLifecycleManager.class)
这里是MongoDBLifecycleManager的实现:

public class MongoDBLifecycleManager implements QuarkusTestResourceLifecycleManager {

    private MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:5.0.10"));

    @Override
    public Map<String, String> start() {
        mongoDBContainer.start();

        return Map.of(
                "quarkus.mongodb.connection-string", mongoDBContainer.getConnectionString(),
                "quarkus.mongodb.database", "testDB");
    }

    @Override
    public void stop() {
        mongoDBContainer.stop();
    }
}

值得注意的是,您的测试将忽略您在application.properties中定义为MongoDB连接参数的内容,并使用方法start返回的内容:

Map.of("quarkus.mongodb.connection-string", mongoDBContainer.getConnectionString(),
       "quarkus.mongodb.database", "testDB");

您可以让其他MongoDB示例在本地机器上运行,并让测试容器在一个随机端口上运行。
在您的pom.xml中,您将需要以下内容:

<dependency>
        <groupId>org.testcontainers</groupId>
            <artifactId>testcontainers</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.testcontainers</groupId>
            <artifactId>junit-jupiter</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.testcontainers</groupId>
            <artifactId>mongodb</artifactId>
            <scope>test</scope>
        </dependency>

相关问题