集成测试
重要的是,能够在无需部署到应用服务器或连接到其他企业基础设施的情况下执行一些集成测试。这样做可以让你测试以下内容:
-
Spring IoC 容器上下文的正确连接。
-
使用 JDBC 或 ORM 工具进行数据访问。这可以包括 SQL 语句的正确性、Hibernate 查询、JPA 实体映射等等。
Spring Framework 在 `spring-test` 模块中提供了对集成测试的一流支持。实际 JAR 文件的名称可能包含发布版本,也可能采用 `org.springframework.test` 的长形式,具体取决于你从哪里获取它(请参阅依赖管理部分以获取解释)。此库包含 `org.springframework.test` 包,其中包含用于使用 Spring 容器进行集成测试的宝贵类。这种测试不依赖于应用服务器或其他部署环境。此类测试运行速度比单元测试慢,但比等效的 Selenium 测试或依赖于部署到应用服务器的远程测试快得多。
单元和集成测试支持以注解驱动的 Spring TestContext Framework 的形式提供。TestContext 框架与实际使用的测试框架无关,这允许在各种环境中(包括 JUnit、TestNG 等)对测试进行检测。
以下部分概述了 Spring 集成支持的高级目标,本章的其余部分将重点介绍专用主题:
集成测试目标
Spring 的集成测试支持具有以下主要目标:
-
管理测试之间的Spring IoC 容器缓存。
-
提供测试夹具实例的依赖注入。
-
提供适用于集成测试的事务管理。
-
提供Spring 特定的基类,以协助开发人员编写集成测试。
接下来的几个部分描述了每个目标,并提供了实现和配置细节的链接。
上下文管理和缓存
Spring TestContext Framework 提供 Spring `ApplicationContext` 实例和 `WebApplicationContext` 实例的一致加载以及这些上下文的缓存。支持加载上下文的缓存非常重要,因为启动时间可能会成为一个问题——不是因为 Spring 本身的开销,而是因为 Spring 容器实例化的对象需要时间来实例化。例如,一个拥有 50 到 100 个 Hibernate 映射文件的项目可能需要 10 到 20 秒才能加载映射文件,在每个测试夹具中运行每个测试之前都要承担这种成本会导致整体测试运行速度变慢,从而降低开发人员的生产力。
测试类通常声明 XML 或 Groovy 配置元数据的资源位置数组——通常在类路径中——或用于配置应用程序的组件类数组。这些位置或类与 `web.xml` 或生产部署的其他配置文件中指定的相同或相似。
默认情况下,一旦加载,配置的 `ApplicationContext` 将在每个测试中重用。因此,设置成本只在每个测试套件中承担一次,后续测试执行会快得多。在此上下文中,“测试套件”指在同一个 JVM 中运行的所有测试——例如,对于给定项目或模块,从 Ant、Maven 或 Gradle 构建运行的所有测试。在极少数情况下,如果测试破坏了应用程序上下文并需要重新加载(例如,通过修改 bean 定义或应用程序对象的状态),TestContext 框架可以配置为在执行下一个测试之前重新加载配置并重建应用程序上下文。
请参阅 上下文管理 和 使用 TestContext 框架进行上下文缓存。
测试夹具的依赖注入
当 TestContext 框架加载您的应用程序上下文时,它可以通过使用依赖注入来选择性地配置您的测试类实例。这提供了一种方便的机制,通过使用应用程序上下文中的预配置 bean 来设置测试夹具。这里的一个强大优势是,您可以在各种测试场景中重用应用程序上下文(例如,用于配置 Spring 管理的对象图、事务代理、`DataSource` 实例等),从而避免为单个测试用例重复复杂的测试夹具设置。
举个例子,考虑一个场景,我们有一个类(`HibernateTitleRepository`)实现了 `Title` 领域实体的数据访问逻辑。我们想编写集成测试来测试以下方面:
-
Spring 配置:基本上,所有与 `HibernateTitleRepository` bean 配置相关的内容是否都正确且存在?
-
Hibernate 映射文件配置:所有内容是否都正确映射,并且是否设置了正确的延迟加载?
-
`HibernateTitleRepository` 的逻辑:此类的配置实例是否按预期执行?
请参阅使用 TestContext 框架 进行测试夹具的依赖注入。
事务管理
在访问真实数据库的测试中,一个常见问题是它们对持久性存储状态的影响。即使您使用开发数据库,状态的更改也可能会影响未来的测试。此外,许多操作(例如插入或修改持久数据)无法在事务外部执行(或验证)。
TestContext 框架解决了这个问题。默认情况下,框架为每个测试创建并回滚一个事务。您可以编写假定事务存在的代码。如果在测试中调用事务代理对象,它们会根据其配置的事务语义正确执行。此外,如果测试方法在为测试管理的事务中运行期间删除了选定表的内容,则事务默认回滚,数据库将恢复到执行测试之前的状态。通过使用在测试的应用程序上下文中定义的 `PlatformTransactionManager` bean,为测试提供事务支持。
如果您希望事务提交(不常见,但偶尔在您希望特定测试填充或修改数据库时很有用),您可以使用 `@Commit` 注解告诉 TestContext 框架使事务提交而不是回滚。
请参阅使用 TestContext 框架 进行事务管理。
集成测试支持类
Spring TestContext Framework 提供了几个 `abstract` 支持类,可以简化集成测试的编写。这些基类提供了与测试框架连接的明确定义钩子,以及方便的实例变量和方法,让您可以访问:
-
`ApplicationContext`,用于执行显式 bean 查找或测试整个上下文的状态。
-
`JdbcTemplate`,用于执行 SQL 语句以查询数据库。您可以使用此类查询来确认与数据库相关的应用程序代码执行前后的数据库状态,Spring 确保此类查询与应用程序代码在同一个事务范围内运行。与 ORM 工具结合使用时,请务必避免 假阳性。
此外,您可能希望创建自己的自定义、应用程序范围的超类,其中包含特定于您项目的实例变量和方法。
请参阅 TestContext 框架 的支持类。