Testcontainers是一个Java库,支持JUnit测试,它提供了常见的数据库,Selenium Web浏览器或其他可以在Docker容器中运行的轻型的一次性实例。
假设我们在本教程中使用maven:
<properties> <junit-jupiter.version>5.4.2</junit-jupiter.version> <testcontainers.version>1.15.0</testcontainers.version> </properties> <dependencies> <dependency> <groupId>org.testcontainers</groupId> <artifactId>testcontainers</artifactId> <version>${testcontainers.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>junit-jupiter</artifactId> <version>${testcontainers.version}</version> <scope>test</scope> </dependency> </dependencies>
|
这里将使用Hoverfly作为被测试的案例。
可以通过使用Java运行Hoverfly或在Hoverfly容器中预加载测试用例。这里使用测试Hoverfly容器:
package com.gkatzioura.hoverfly.docker; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.testcontainers.containers.BindMode; import org.testcontainers.containers.GenericContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @Testcontainers public class ContainerBasedSimulation { private static final String SIMULATION_HOST_PATH = ContainerBasedSimulation.class.getClassLoader().getResource("simulation.json").getPath(); @Container public static GenericContainer gcs = new GenericContainer("spectolabs/hoverfly") .withExposedPorts(8888) .withExposedPorts(8500) .withCommand("-webserver","-import","/var/hoverfly/simulation.json") .withClasspathResourceMapping("simulation.json","/var/hoverfly/simulation.json" ,BindMode.READ_ONLY); @Test void testHttpGet() { var hoverFlyHost = gcs.getHost(); var hoverFlyPort = gcs.getMappedPort(8500); var client = HttpClient.newHttpClient(); var request = HttpRequest.newBuilder() .uri(URI.create("http://"+hoverFlyHost+":"+ hoverFlyPort +"/user")) .build(); var res = client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) .thenApply(HttpResponse::body) .join(); Assertions.assertEquals("{\"username\":\"test-user\"}",res); } }
|
讲解如下:
Jupiter集成需要@Testcontainers批注。
@Testcontainers public class ContainerBasedSimulation { }
|
这时需要使用的容器的镜像还没有加载,这时使用GenericContainer :
@Container public static GenericContainer gcs = new GenericContainer("spectolabs/hoverfly")
|
由于我们要将模拟应用加载到容器,因此需要从主机上设置模拟路径。通过使用withClasspathResourceMapping,我们可以直接在类路径中指定文件,例如测试资源。
.withClasspathResourceMapping("simulation.json","/var/hoverfly/simulation.json",BindMode.READ_ONLY);
|
Hoverfly需要暴露模拟和管理端口,因此我们将指示Testcontainer暴露那些端口并将其映射到主机。
new GenericContainer("spectolabs/hoverfly") .withExposedPorts(8888) .withExposedPorts(8500)
|
我们需要在容器上放置一个模拟。通过使用withFileSystemBind,我们可以指定本地路径和容器上的路径。
... .withFileSystemBind(SIMULATION_HOST_PATH,"/var/hoverfly/simulation.json" ,BindMode.READ_ONLY) ...
|
此外,docker映像可能还需要一些其他命令,因此我们将使用.withCommand来传递所需的命令。
... .withCommand("-webserver","-import","/var/hoverfly/simulation.json") ...
|
从技术上讲,我们可以说已经准备好连接到容器,但是在运行测试容器时,这时外部正常访问不能通过指定用于绑定的端口访问该容器,因为如果测试并行运行,将会发生冲突。因此,测试容器要做的就是将容器的裸露端口映射到随机的本地端口。这样避免了端口冲突。
@Test void testHttpGet() { var hoverFlyHost = gcs.getHost(); var hoverFlyPort = gcs.getMappedPort(8500); var client = HttpClient.newHttpClient(); var request = HttpRequest.newBuilder() .uri(URI.create("http://"+hoverFlyHost+":"+ hoverFlyPort +"/user")) .build(); var res = client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) .thenApply(HttpResponse::body) .join(); Assertions.assertEquals("{\"username\":\"test-user\"}",res); }
|
使用GenericContainer.getMappedPort(8500),我们可以获取用于与容器交互的端口。另外,getHost()也是必不可少的,因为它并不总是直接指向localhost。
最后:
docker ps >04a322447226 testcontainers/ryuk:0.3.0 "/app"
|