跳到主要内容

集成测试

ChatGPT-4o-mini 中英对照 Integration Testing

在不需要部署到应用服务器或连接到其他企业基础设施的情况下,能够进行一些集成测试是很重要的。这样可以让你测试以下内容:

  • 正确连接您的 Spring IoC 容器上下文。

  • 使用 JDBC 或 ORM 工具进行数据访问。这可以包括 SQL 语句的正确性、Hibernate 查询、JPA 实体映射等。

Spring 框架在 spring-test 模块中提供了一流的集成测试支持。实际的 JAR 文件名称可能包含发布版本,并且可能还会以长格式 org.springframework.test 表示,这取决于你从哪里获取它(有关解释,请参见 依赖管理部分)。该库包含 org.springframework.test 包,其中包含用于与 Spring 容器进行集成测试的有价值的类。这种测试不依赖于应用服务器或其他部署环境。这类测试的运行速度比单元测试慢,但比等效的 Selenium 测试或依赖于部署到应用服务器的远程测试快得多。

单元和集成测试支持以注解驱动的 Spring TestContext Framework 形式提供。TestContext 框架与实际使用的测试框架无关,这允许在各种环境中对测试进行工具化,包括 JUnit、TestNG 等。

以下部分概述了 Spring 集成支持的高层目标,接下来的章节则专注于特定主题:

集成测试的目标

Spring 的集成测试支持有以下主要目标:

接下来的几个部分将描述每个目标,并提供实施和配置细节的链接。

上下文管理和缓存

Spring TestContext 框架提供了一致的加载 Spring ApplicationContext 实例和 WebApplicationContext 实例的功能,并且支持对这些上下文的缓存。支持加载上下文的缓存非常重要,因为启动时间可能会成为一个问题 — 这并不是因为 Spring 本身的开销,而是因为 Spring 容器实例化的对象需要时间。例如,一个包含 50 到 100 个 Hibernate 映射文件的项目可能需要 10 到 20 秒来加载这些映射文件,在每个测试夹具中运行每个测试之前承担这个成本,会导致整体测试运行变慢,从而降低开发者的生产力。

测试类通常声明一个资源位置数组,用于 XML 或 Groovy 配置元数据 — 通常在类路径中 — 或者一个组件类数组,用于配置应用程序。这些位置或类与在 web.xml 或其他生产部署配置文件中指定的相同或相似。

默认情况下,一旦加载,配置的 ApplicationContext 会在每个测试中被重复使用。因此,设置成本仅在每个测试套件中发生一次,后续的测试执行速度要快得多。在这个上下文中,“测试套件”一词指的是在同一个 JVM 中运行的所有测试 — 例如,从 Ant、Maven 或 Gradle 构建中为给定项目或模块运行的所有测试。在不太可能的情况下,如果某个测试损坏了应用程序上下文并需要重新加载(例如,通过修改 bean 定义或应用程序对象的状态),则可以配置 TestContext 框架在执行下一个测试之前重新加载配置并重建应用程序上下文。

查看 Context ManagementContext Caching 与 TestContext 框架。

测试夹具的依赖注入

当 TestContext 框架加载您的应用程序上下文时,它可以选择通过使用依赖注入来配置您的测试类实例。这提供了一种方便的机制,通过使用来自您的应用程序上下文的预配置 bean 来设置测试夹具。这里的一个重要好处是,您可以在各种测试场景中重用应用程序上下文(例如,用于配置 Spring 管理的对象图、事务代理、DataSource 实例等),从而避免为单个测试用例重复复杂的测试夹具设置。

作为一个例子,考虑一个场景,我们有一个类(HibernateTitleRepository),它实现了 Title 领域实体的数据访问逻辑。我们想编写集成测试,测试以下几个方面:

  • Spring 配置:基本上,HibernateTitleRepository bean 的配置是否正确且齐全?

  • Hibernate 映射文件配置:所有映射是否正确,懒加载设置是否到位?

  • HibernateTitleRepository 的逻辑:该类的配置实例是否按预期执行?

查看使用 TestContext 框架 的测试夹具的依赖注入。

事务管理

在访问真实数据库的测试中,一个常见的问题是它们对持久性存储状态的影响。即使使用开发数据库,对状态的更改也可能影响未来的测试。此外,许多操作 — 例如插入或修改持久数据 — 无法在事务之外执行(或验证)。

TestContext 框架解决了这个问题。默认情况下,该框架为每个测试创建并回滚一个事务。您可以编写可以假设存在事务的代码。如果您在测试中调用事务代理对象,它们将根据其配置的事务语义正确地执行。此外,如果测试方法在为测试管理的事务中运行时删除了选定表的内容,默认情况下,事务将回滚,数据库将恢复到执行测试之前的状态。通过在测试的应用程序上下文中使用定义的 PlatformTransactionManager bean,为测试提供了事务支持。

如果您希望事务提交(虽然不常见,但在您希望特定测试填充或修改数据库时偶尔有用),您可以通过使用 @Commit 注解告诉 TestContext 框架使事务提交而不是回滚。

查看使用 TestContext framework 的事务管理。

集成测试的支持类

Spring TestContext 框架提供了几个 abstract 支持类,这些类简化了集成测试的编写。这些基础测试类提供了明确的钩子,以便于测试框架的使用,以及方便的实例变量和方法,让你可以访问:

  • ApplicationContext,用于执行显式的 bean 查找或测试上下文的整体状态。

  • JdbcTemplate,用于执行 SQL 语句以查询数据库。您可以使用这样的查询在执行与数据库相关的应用程序代码之前和之后确认数据库状态,并且 Spring 确保这些查询在与应用程序代码相同的事务范围内运行。当与 ORM 工具结合使用时,请务必避免 false positives

此外,您可能想要创建自己的自定义应用程序级超类,其中包含特定于您项目的实例变量和方法。

请参阅 TestContext 框架 的支持类。