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