Integration Testing
能够执行一些集成测试而不必部署到应用程序服务器或连接到其他企业基础架构非常重要。这样做可以让你测试如下事项:
-
正确的 Spring IoC 容器上下文的接线。
-
使用 JDBC 或 ORM 工具进行数据访问。这可以包括如 SQL 语句、Hibernate 查询、JPA 实体映射等的正确性之类的内容。
Spring Framework 在 spring-test
模块中为集成测试提供了一流的支持。实际 JAR 文件的名称可能包含版本号,也可能采用较长的 org.springframework.test
形式,具体取决于您在哪里获得它(有关说明,请参阅 section on Dependency Management )。此库包含 org.springframework.test
软件包,其中包含用于使用 Spring 容器进行集成测试的有价值的类。此测试不依赖于应用程序服务器或其他部署环境。此类测试的运行速度比单元测试慢,但比依赖于部署到应用程序服务器的 Selenium 测试或远程测试快得多。
单元和集成测试支持以基于注释的 Spring TestContext Framework 的形式提供。TestContext 框架与实际使用的测试框架无关,这允许在各种环境中对测试进行检测,包括 JUnit、TestNG 和其他环境。
以下部分概述了 Spring 集成支持的高级目标,本章的其余部分重点介绍专门的主题:
Goals of Integration Testing
Spring 的集成测试支持具有以下主要目标:
-
在测试之间管理 Spring IoC container caching。
-
提供适合集成测试的 transaction management。
-
提供可帮助开发人员编写集成测试的 Spring-specific base classes。
以下部分介绍了每个目标,并提供了实现和配置详细信息的链接。
Context Management and Caching
Spring TestContext Framework 提供一致加载 Spring ApplicationContext
实例和 WebApplicationContext
实例以及缓存这些上下文。对加载的上下文提供缓存支持非常重要,因为启动时间可能会成为问题——这并不是因为 Spring 本身开销太大,而是因为 Spring 容器实例化的对象需要时间来实例化。例如,一个包含 50 到 100 个 Hibernate 映射文件项目可能需要 10 到 20 秒来加载映射文件,每个测试夹具中运行每个测试之前都会产生该成本,从而导致整体测试运行速度变慢,降低开发人员的生产率。
测试类通常会声明 XML 或 Groovyconfiguration 元数据(通常在类路径中)的资源位置数组,或用于配置应用程序的组件类数组。这些位置或类与 web.xml
或生产部署的其他配置文件中指定的位置或类相同或相似。
在默认情况下,配置的 ApplicationContext
在加载后可用于每次测试。因此,每个测试套件只产生一次安装费用,随后的测试执行速度会快很多。在此上下文中,“测试套件”一词表示在同一 JVM 中运行的所有测试,例如,给定项目模块针对 Ant、Maven 或 Gradle 进行构建时运行的所有测试。在不太可能的情况下,如果某个测试破坏了应用程序上下文并需要重新加载(例如,修改 Bean 定义或应用程序对象的状况),则可以将 TestContext 框架配置为在执行下一个测试之前重新加载配置并重建应用程序上下文。
使用 TestContext 框架,请参阅 Context Management 和 Context Caching 。
Dependency Injection of Test Fixtures
当 TestContext 框架加载您的应用程序上下文时,它可以借助依赖注入功能选择性地配置测试类实例。这提供了一种便捷机制,可使用应用程序上下文中的预置 Bean 来设置测试夹具。这其中有一个很大的好处是,您可以在各种测试场景中重新利用应用程序上下文(例如,配置 Spring 管理的对象图、事务代理、DataSource
实例等),从而避免为个别测试用例复制复杂的测试夹具安装。
例如,假设有一个类 (HibernateTitleRepository
),用于实现 Title
域实体的数据访问逻辑。我们希望编写集成测试来测试以下区域:
-
Spring 配置:基本上,与
HibernateTitleRepository
bean 的配置相关的每一件事都正确且存在吗? -
Hibernate 映射文件配置:是否正确映射了所有内容,并且正确设置了延迟加载设置?
-
`HibernateTitleRepository`的逻辑:该类的配置实例是否如预期般执行?
使用 TestContext framework 查看测试 fixture 的依赖注入。
Transaction Management
在访问真实数据库的测试中,一个常见问题是它们对持久性存储状态的影响。即使在使用开发数据库时,对状态的更改也可能会影响后续测试。此外,许多操作(例如插入或修改持久性数据)无法在事务外部执行(或验证)。
TestContext 框架解决了这个问题。在默认情况下,该框架会为每个测试创建并回滚一个事务。您可以编写可以假定存在事务的代码。如果您在测试中调用事务代理对象,则它们会根据事务语义配置正确运行。此外,如果某个测试方法在为测试管理的事务中运行时删除了特定表的内容,则该事务会在默认情况下回滚,并且会在执行测试前数据库返回到其原有状态。事务支持会通过使用测试的应用程序上下文中定义的 PlatformTransactionManager
Bean 来提供给测试。
如果您希望提交事务(这并不常见,但当您希望特定测试填充或修改数据库时偶尔会很有用),您可以通过使用 @Commit
注释告诉 TestContext 框架提交事务,而不是回滚事务。
使用 TestContext framework 查看事务管理。
Support Classes for Integration Testing
Spring TestContext 框架提供了几个 abstract
支持类,可简化集成测试的编写。这些基本测试类提供了进入测试框架的明确挂钩以及方便的实例变量和方法,可让您访问:
-
`ApplicationContext`用于执行显式 bean 查找或测试上下文的整体状态。
-
`JdbcTemplate`用于执行 SQL 语句以查询数据库。您可以在数据库相关应用代码执行前和执行后使用此类查询来确认数据库状态,且 Spring 确保此类查询在与应用代码相同的范围的事务中运行。与 ORM 工具结合使用时,务必避免使用 false positives。
此外,您可能还希望创建自己的自定义应用范围超类的实例变量和方法,这些变量和方法特定于您的项目。
查看 TestContext framework 的支持类。