TestContainers库简介
1. 简介
**在本教程中,我们将研究 Java TestContainers库。**它允许我们在测试中使用 Docker 容器。因此,我们可以编写依赖于外部资源的独立集成测试。
我们可以在测试中使用任何具有 docker 镜像的资源。例如,有用于数据库、Web 浏览器、Web 服务器和消息队列的镜像。因此,我们可以在测试中将它们作为容器运行。
2. 要求
TestContainers库可用于 Java 8 及更高版本。此外,它与 JUnit Rules API 兼容。
首先,让我们为核心功能定义 maven 依赖项:
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.11.4</version>
</dependency>
还有一些专门用于容器的模块。在本教程中,我们将使用PostgreSQL和 Selenium。
让我们添加相关的依赖项:
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql </artifactId>
<version>1.11.4</version>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>selenium </artifactId>
<version>1.11.4</version>
</dependency>
我们可以在 Maven Central 上找到最新版本。 此外,我们需要 Docker 来运行容器。有关安装说明,请参阅Docker 文档 。 确保您能够在测试环境中运行 Docker 容器。
3. 用法
让我们配置一个通用的容器规则:
@ClassRule
public static GenericContainer simpleWebServer
= new GenericContainer("alpine:3.2")
.withExposedPorts(80)
.withCommand("/bin/sh", "-c", "while true; do echo "
+ "\"HTTP/1.1 200 OK\n\nHello World!\" | nc -l -p 80; done");
我们通过指定一个 docker 镜像名称来构建一个GenericContainer测试规则。然后,我们使用构建器方法对其进行配置:
- 我们使用 withExposedPorts从容器中暴露一个端口
- withCommand定义了一个容器命令。它将在容器启动时执行。
该规则使用 @ClassRule 进行注解。因此,它将在该类中的任何测试运行之前启动 Docker 容器。所有方法执行完毕后,容器将被销毁。
如果您应用*@Rule*注解,GenericContainer规则将为每个测试方法启动一个新容器。当该测试方法完成时,它将停止容器。
我们可以使用 IP 地址和端口与容器中运行的进程进行通信:
@Test
public void givenSimpleWebServerContainer_whenGetReuqest_thenReturnsResponse()
throws Exception {
String address = "http://"
+ simpleWebServer.getContainerIpAddress()
+ ":" + simpleWebServer.getMappedPort(80);
String response = simpleGetRequest(address);
assertEquals(response, "Hello World!");
}
4. 使用方式
测试容器有多种使用模式。我们看到了一个运行 GenericContainer 的示例。
TestContainers库还具有具有专门功能的规则定义。它们用于 MySQL、PostgreSQL 等常见数据库的容器;和其他人喜欢网络客户端。
尽管我们可以将它们作为通用容器运行,但特化提供了扩展的便利方法。
4.1. 数据库
假设我们需要一个用于数据访问层集成测试的数据库服务器。我们可以借助 TestContainers 库在容器中运行数据库。
例如,我们使用PostgreSQLContainer规则启动一个 PostgreSQL 容器。然后,我们可以使用辅助方法。这些是 用于数据库连接的getJdbcUrl、getUsername、getPassword :
@Rule
public PostgreSQLContainer postgresContainer = new PostgreSQLContainer();
@Test
public void whenSelectQueryExecuted_thenResulstsReturned()
throws Exception {
String jdbcUrl = postgresContainer.getJdbcUrl();
String username = postgresContainer.getUsername();
String password = postgresContainer.getPassword();
Connection conn = DriverManager
.getConnection(jdbcUrl, username, password);
ResultSet resultSet =
conn.createStatement().executeQuery("SELECT 1");
resultSet.next();
int result = resultSet.getInt(1);
assertEquals(1, result);
}
也可以将 PostgreSQL 作为通用容器运行。但是配置连接会更加困难。
4.2. 网络驱动程序
另一个有用的场景是使用 Web 浏览器运行容器。 BrowserWebDriverContainer规则允许在 docker -selenium容器中运行Chrome和 Firefox 。然后,我们使用RemoteWebDriver 管理它们。
这对于自动化 Web 应用程序的 UI/验收测试非常有用:
@Rule
public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer()
.withCapabilities(new ChromeOptions());
@Test
public void whenNavigatedToPage_thenHeadingIsInThePage() {
RemoteWebDriver driver = chrome.getWebDriver();
driver.get("http://example.com");
String heading = driver.findElement(By.xpath("/html/body/div/h1"))
.getText();
assertEquals("Example Domain", heading);
}
4.3. 码头工人撰写
如果测试需要更复杂的服务,我们可以在docker-compose文件中指定它们 :
simpleWebServer:
image: alpine:3.2
command: ["/bin/sh", "-c", "while true; do echo 'HTTP/1.1 200 OK\n\nHello World!' | nc -l -p 80; done"]
然后,我们使用DockerComposeContainer规则。此规则将启动并运行 compose 文件中定义的服务。
我们使用getServiceHost和getServicePost方法来建立到服务的连接地址:
@ClassRule
public static DockerComposeContainer compose =
new DockerComposeContainer(
new File("src/test/resources/test-compose.yml"))
.withExposedService("simpleWebServer_1", 80);
@Test
public void givenSimpleWebServerContainer_whenGetReuqest_thenReturnsResponse()
throws Exception {
String address = "http://" + compose.getServiceHost("simpleWebServer_1", 80) + ":" + compose.getServicePort("simpleWebServer_1", 80);
String response = simpleGetRequest(address);
assertEquals(response, "Hello World");
}