Spring 的集成测试支持有以下主要目的:
- 在测试之间管理 Spring IoC 容器的缓存
- 提供测试装置实例的依赖性注入。
- 提供适合集成测试的事务管理。
- 提供特定于 Spring 的基类,帮助开发人员编写集成测试。
管理 Spring IoC 容器的缓存
Spring TestContext 框架提供了 Spring ApplicationContext 实例和 WebApplicationContext 实例的一致加载,以及这些上下文的缓存。对加载的上下文的缓存支持很重要,因为启动时间可能成为一个问题 — 不是因为 Spring 本身的开销,而是因为 Spring 容器实例化的对象需要时间来实例化。例如,一个有 50 到 100 个 Hibernate 映射文件的项目可能需要 10 到 20 秒来加载映射文件,而在运行每个测试夹具中的每个测试之前产生的成本会导致整个测试运行速度变慢,从而降低开发人员的工作效率。
测试类通常声明 XML 或 Groovy 配置元数据的资源位置数组 — 通常在 classpath 中 — 或用于配置应用程序的组件类数组。这些位置或类与 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 框架提供了几个抽象的支持类,简化了集成测试的编写。这些基础测试类为测试框架提供了定义明确的钩子,以及方便的实例变量和方法,让你访问:
- ApplicationContext:用于执行显式 Bean 查找或测试整个上下文的状态。
- JdbcTemplate:用于执行查询数据库的 SQL 语句。你可以在执行数据库相关的应用程序代码之前和之后使用这种查询来确认数据库状态, Spring 确保这种查询在与应用程序代码相同的事务范围内运行。当与 ORM 工具一起使用时,要注意避免 误报。
此外,你可能想创建你自己的、应用范围内的超类,带有实例变量和具体到你项目的方法。
参见 TestContext 框架 的支持类。