Java 应用程序的混合测试框架
微信搜索关注《Java学研大本营》,加入读者群,分享更多精彩
这篇博文演示了如何在基于 Java Spring 引导的后端应用程序中使用 Testcontainers.org 库编写集成测试。
集成测试
集成测试是软件测试的一个阶段,其中将各个软件模块组合在一起并作为一个整体进行测试。集成测试旨在评估我们的代码在与其他组件(如数据库、外部服务等)交互时如何运行。不仅在快乐路径实例中,而且特别是在第三方服务可能以意外 HTTP 响应的边缘情况下代码并在预定超时后提供 HTTP 响应。
集成测试的数量
我们需要在不同的测试类型之间保持适当的平衡。集成测试不能成为任何应用程序的核心,但集成测试比其他类型的测试更省力。所以我们应该至少让我们的应用程序包含集成测试。
对于理想的案例场景,金字塔测试结构可以向我们展示不同类型测试的比例。
最不常见的测试类型最好是手动测试和系统测试。根据我们的经验,我们认为集成测试比单元测试多 25%,尽管这因应用程序而异。
Testcontainers 库在集成测试中的作用
正如我们在集成测试中所知道的那样,我们不模拟数据源那么我们如何才能进一步进行呢?我们无法连接到实际数据源进行集成测试。在这里,出现了图片中的TestContainer。
Testcontainers 是一个 JVM 库,允许用户运行和管理 Docker 镜像并从 Java 代码控制它们。我们可以创建不同数据源的实例,如Postgresql、Elastic search等。
测试容器如何使集成测试更容易
-
当我们尝试运行测试用例时,这些实例将在docker容器内创建。
-
我们可以很容易地获取这些实例的端点,并可以覆盖 application.properties 或 pom.xml 文件中定义的实际端点。
-
我们可以将测试用例所需的数据放入测试容器中
-
我们可以看看这些测试容器中存储的数据是什么。我们只需要在调试模式下执行测试用例,添加断点并使用 docker 命令进入测试容器,就像我们对在 docker 容器内运行的其他实例所做的那样。
-
最后,当测试执行结束时,这些容器将自动销毁。
使用测试容器的测试框架的先决条件
-
在你的机器上安装 Docker
-
确保在测试的类路径中有Spring Boot 和 Spring Cloud。如果您需要选择一个版本。如果您不使用 Spring Cloud — 使其仅通过测试范围内的此依赖项用于测试
< dependency >
< groupId > org.springframework.cloud </ groupId >
< artifactId > spring-cloud-starter-bootstrap </ artifactId >
< version > 3.1.3 </ version >
< scope > test </ scope >
</ dependency >
使用 TestContainers 进行基本集成测试
让我们使用 JUnit 5 和 Spring Boot 设置一个基本的集成测试。假设我们的 spring boot 应用程序连接到两个不同的数据源 PostgreSQL 和 Aerospike。
我们可以使用两种方式将这些数据源与我们的应用程序集成以进行集成测试 -
-
直接使用测试容器依赖项
-
使用嵌入式测试容器依赖项 让我们看看使用第一种方式集成 Postgresql,使用第二种方式集成 Aerospike。
使用嵌入式测试容器依赖项的 Aerospike 集成
集成 Aerospike 测试容器的最简单方法是使用嵌入式aerospike 依赖项。这是 Aerospike 测试容器的包装器。这种依赖将为我们引导一切。
集成步骤-
-
在 pom.xml 文件中添加此依赖项。
< dependency >
< groupId > com.playtika.testcontainers </ groupId >
< artifactId > embedded-aerospike </ artifactId >
< version > 2.2.5 </ version >
< scope > test </ scope >
</ dependency >
-
添加 Aerospike 配置属性,例如在 bootstrap.properties 文件中使用哪个版本,如下所示。
#aerospike test container configs
embedded.aerospike.dockerImage=aerospike/aerospike-server:6.0.0.2
embedded.aerospike.time-travel.enabled=false
-
我们可以像这样获取 Aerospike 主机/端口/命名空间信息
embedded.aerospike.host embedded.aerospike.port embedded.aerospike.namespace
-
使用这些新属性覆盖 application.properties 文件中定义的 Aerospike 属性,如下所示
#aerospike aerospike.hosts
= [{ "host" : "${embedded.aerospike.host}" , "port" : ${embedded.aerospike.port} }]
aerospike.namespace = ${embedded.aerospike.namespace}
-
现在,我们都准备好使用 aerospike 测试容器,就像它托管在服务器上一样。我们可以进行所有的 CRUD 操作。
Postgres Integration 直接使用 Test container dependency
如果我们不想使用嵌入式 PostgreSQL测试容器,那么我们必须添加一些额外的依赖项和配置来启动它。虽然它给了我们更多的控制权。
集成步骤-
-
在 pom.xml 中添加以下依赖项以及来自maven 存储库的所需版本。
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.16.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.16.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>1.16.3</version>
<scope>test</scope>
</dependency>
-
添加带有
@TestConfiguration
注释的配置类,以指定启动 Postgres 容器所需的属性并添加启动指令。 -
postgres 容器启动后,使用此服务器的属性覆盖 application.properties 文件中定义的 Postgres 属性,如下所示
@TestConfiguration
public class PostgresSQLTestContainerConfig
extends PostgreSQLContainer<PostgresSQLTestContainerConfig> {
private static final String DOCKER_IMAGE_VERSION = "postgres:latest";
private static final PostgresSQLTestContainerConfig POSTGRES_SQL_TEST_CONTAINER =
new PostgresSQLTestContainerConfig().withReuse(true);
static {
POSTGRES_SQL_TEST_CONTAINER.start();
System.setProperty("spring.datasource.url", POSTGRES_SQL_TEST_CONTAINER.getJdbcUrl());
System.setProperty("spring.datasource.username", POSTGRES_SQL_TEST_CONTAINER.getUsername());
System.setProperty("spring.datasource.password", POSTGRES_SQL_TEST_CONTAINER.getPassword());
}
public PostgresSQLTestContainerConfig() {
super(DOCKER_IMAGE_VERSION);
}
@Override
public void stop() {
// do nothing, JVM handles shut down
}
}
-
现在,我们都设置好使用 Postgres 测试容器,就像它托管在服务器上一样。我们可以进行所有的 CRUD 操作。
使用 TestContainers 库的优势
-
我们可以在实际组件上运行测试,例如 PostgreSQL 数据库(例如分区或 JSON 操作),而不是使用不提供 Postgres 特定功能的 H2 数据库。
-
我们可以通过编程方式模拟来自外部服务的超时(例如,通过配置 MockServer 以大于我们 HTTP 客户端中设置的超时的延迟进行响应),模拟我们的应用程序未明确支持的 HTTP 代码,并在HTTP 通信..
-
我们可以在没有 Internet 连接的情况下运行测试。这对于那些在旅途中或我们的互联网连接速度很慢的人来说是有利的(当我们已经运行过一次并且容器中没有版本更改时)。
-
甚至一个集成测试就可以确认应用程序上下文是否正确启动以及数据库迁移脚本(例如 Flyway)是否运行无误。
-
我们可以使用 LocalStack 或 AWS 提供的 Docker 镜像来模拟 AWS 服务。它将降低成本、简化管理程序并使我们的构建脱机。
使用 TestContainers 库的缺点
-
持续集成机器(如 Jenkins)必须更大(构建使用更多 RAM 和 CPU)。
-
本地计算机应该是相当强大的。运行大量 Docker 镜像可能会耗尽大量资源。
-
使用 TestContainers 的集成测试可能并不总是足够的。例如,在使用模拟服务器容器测试 REST 响应时,我们可能会错过对实际 API 的更改。如果我们不在集成测试中反映它,我们的代码仍然有可能在生产中崩溃。我们可能会考虑通过 Spring Cloud Contract 使用 Contract Testing 来降低风险。
推荐书单
《项目驱动零起点学Java》
《项目驱动零起点学Java》共分 13 章,围绕 6 个项目和 258 个代码示例,分别介绍了走进Java 的世界、变量与数据类型、运算符、流程控制、方法、数组、面向对象、异常、常用类、集合、I/O流、多线程、网络编程相关内容。《项目驱动零起点学Java》总结了马士兵老师从事Java培训十余年来经受了市场检验的教研成果,通过6 个项目以及每章的示例和习题,可以帮助读者快速掌握Java 编程的语法以及算法实现。扫描每章提供的二维码可观看相应章节内容的视频讲解。
《项目驱动零起点学Java》贯穿6个完整项目,经过作者多年教学经验提炼而得,项目从小到大、从短到长,可以让读者在练习项目的过程中,快速掌握一系列知识点。
马士兵,马士兵教育创始人,毕业于清华大学,著名IT讲师,所讲课程广受欢迎,学生遍布全球大厂,擅长用简单的语言讲授复杂的问题,擅长项目驱动知识的综合学习。马士兵教育获得在线教育“名课堂”奖、“最受欢迎机构”奖。
赵珊珊,从事多年一线开发,曾为国税、地税税务系统工作。拥有7年一线教学经验,多年线上、线下教育的积累沉淀,培养学员数万名,讲解细致,脉络清晰。
购买链接:https://item.jd.com/13607758.html
精彩回顾
微信搜索关注《Java学研大本营》
访问【IT今日热榜】,发现每日技术热点