15. 集成测试

15. 集成测试

15.1 总览

无需部署应用程序到服务器或连接到其他企业基础架构即可执行一些集成测试,这一点非常重要。这将使开发者能够测试以下内容:

  1. 正确织入Spring IoC容器上下文。
  2. 使用JDBC或ORM工具的数据访问。例如,正确的sql语句、Hibernate的查询、JPA的实体匹配等。

Spring框架在spring-test模块中为集成测试提供了优秀的支持。实际jar文件的名称可能包含发行版本,也可能位于long org.springframework.test那张长长的表单中,具体取决于从哪儿获取它(请参看“依赖管理”一节的解释)。这个库包含org.springframework.test包,它包含了用Spring容器进行集成测试的重要类。这些测试不依赖于应用程序服务器或其他环境部署。这些测试比单元测试运行速度要慢,但要比相同功能的Selenium测试或依赖部署到应用程序服务器的远程测试快得多。
在Spring 2.5或更高版本中,单元测试和集成测试都支持以注解驱动的Spring TestContext框架(第15.5节)形式提供。TestContext框架不受实际使用的测试框架影响,因此能在各种环境中进行测试,包括JUnit、TestNG等等。

15.2 集成测试的目标

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

  1. 为了管理在测试执行期间的Spring Ioc容器缓存(第15.2.1节)。
  2. 为了提供依赖注入相关的测试工具实例(第15.2.2节)。
  3. 为了提供用于集成测试的事务管理(第15.2.3节)。
  4. 为了提供帮助开发人员编写集成测试的,特定于Spring的基类(第15.2.4节)。

接下来的几节将介绍每个目标,并提供实现和配置详细信息的链接。

15.2.1 上下文管理和缓存

Spring TestContext框架提供了对Spring ApplicationContexts和WebApplicationContexts的相应加载以及这些上下文的缓存。对加载的上下文的缓存的支持非常重要,因为启动时间可能会成为一个问题 – 不是因为Spring本身的开销,而是因为Spring容器实例化的对象需要时间来实例化。例如,拥有50到100个Hibernate映射文件的项目可能需要10到20秒的时间才能加载映射文件,并且在每个测试中运行测试之前都必须承受该时间成本,这会降低整体测试的效率,从而降低开发者的工作效率。
测试类通常会为XML或Groovy配置元数据集中声明资源位置数组(通常位于类路径)或用于配置应用程序的一组注解类。这些位置或类与用于生产部署的web.xml或其他指定的配置文件是类似的。
默认的情况下,ApplicationContext配置一旦加载即可在每个测试中重用。因此,每个测试套件只需承受一次设置成本,那么随后的测试执行速度就会快很多了。在这种情况下,术语“测试套件”意味着所有的测试都运行在同一个JVM中 - 例如,对于给定的项目或模块,所有的测试都是从Ant、Maven或Gradle构建的。在不太可能的情况下, 测试会破坏应用程序上下文,并会需要重新加载 - 例如,修改bean定义或应用程序对象的状态 - 可以配置TestContext框架用于重新加载配置并重建应用程序上下文,然后执行下一步测试。
参看第15.5.4 节“上下文管理”和第15.5.4.10 节“上下文缓存”了解测试上下文框架的更多内容。

15.2.2 测试工具的依赖注入

当使用TestContext框架加载应用程序上下文时,可以通过依赖注入有选择性地配置测试类的实例。这为在应用程序上下文使用预先配置的bean套件提供了方便机制。 这样做的的优势是:可以在各种测试场景(例如,配置Spring管理的对象、事务代理、数据源等)中重复使用应用程序上下文,从而避免为单个测试用例重复配置复杂的测试设置。
举个例子:假设有HibernateTitleRepository类,它实现了Title字段实体的数据访问逻辑。现在需要编写包含以下内容的集成测试:

  1. Spring配置:所有与HibernateTitleRepository bean相关的配置是否正确表达?
  2. Hibernate映射文件配置:是否正确映射了所有内容,是否正确配置了lazy-loading?
  3. HibernateTitleRepository的逻辑:此类的配置实例是否预期执行?

更多,请参看TestContext框架对测试装置的依赖注入(第15.5.5节)。

15.2.3 事务管理

访问真实数据库进行测试时,有一个常见的问题就是测试可能影响持久性数据的状态。即使是使用开发数据库,对状态的更改也可能影响将来的测试。另外,许多操作 - 例如插入或修改持久数据 - 不能在事务之外执行(或验证)。
TestContext框架解决了这个问题。默认情况下, 框架会创建并回滚每个测试的事务。开发者只需编写可以带事务的代码。如果在测试中调用事务代理对象,那么将会根据这个配置的事务性语义作出正确的行为。此外,如果测试方法在为测试管理的事务内运行时删除所选表的内容时,该事务在默认情况下会回滚,并且数据库将在执行测试之前返回到原来的状态。事务性支持通过在测试的应用程序上下文中定义的PlatformTransactionManager bean提供。
如果开发者希望事务被提交? - 即有一个特殊的测试希望可以新增或修改数据库 - 那么可以配置TestContext框架将事务提交,而不执行@commit回滚。
更多参看第15.5.7节,使用TestContext框架的事务管理。

15.2.4 支持集成测试的类

Spring TestContext框架提供一些抽象支持类,可以简化集成测试的代码编程。这些基本测试类为测试框架和便捷的实例变量和方法提供了良好定义的钩子,开发者能用于:

  1. ApplicationContext用于执行显式的bean查找或测试整个上下文状态。
  2. 提供用于执行SQL语句来查询数据库的JdbcTemplate。 在执行数据库相关的应用程序代码之前和之后,可以使用这种查询来确认数据库状态,Spring确保这些查询在与应用程序代码相同的事务范围内运行。当与ORM工具一起使用时,一定要避免误报。

另外,开发者可能需要创建自定义的,能应用在整个程序范围的超类,包含特定于项目的实例变量和方法。参看第15.5.9节,用于TestContext框架的支持类。

15.3 JDBC测试支持

org.springframework.test.jdbc包包含JdbcTestUtils类,它是jdbc相关的实用工具的集合,目的是简化标准数据库测试方案。具体地说,JdbcTestUtils提供了以下静态实用工具方法。

  1. countRowsInTable(…):计算给定表的行数;
  2. countRowsInTableWhere (…):使用提供的where子句计算给定表中的行数;
  3. deleteFromTables(…):删除指定表的所有行;
  4. deleteFromTableWhere(…):使用提供的where子句从给定表中删除行;
  5. dropTables(…):彻底删除指定的表。

请注意,AbstractTransactionalJUnit4SpringContextTestsAbstractTransactionalTestNGSpringContextTests提供了在JdbcTestUtils中委托给上述方法的便利方法。

spring-jdbc模块提供了对配置和启动嵌入式数据库的支持,可用于与数据库交互的集成测试。有关详细信息,请参见地19.8节“嵌入数据库的支持”和第19.8.5节“使用嵌入数据库测试数据访问的逻辑”。

15.4 注解

15.4.1 Spring测试注解

Spring框架提供了以下一组特定于Spring的注解,能让开发者在单元和集成测试中使用TestContext框架。有关的详细信息(包括默认属性值、属性别名等),请参看相应的javadocs。

15.4.1.1 @BootstrapWith注解

@BootstrapWith是一个类级注解,用于配置Spring TestContext框架的引导。具体地说, @BootstrapWith用于指定自定义的TestContextBootstrapper。有关详细信息,请参看第15.5.2节“TestContext的引导”。

15.4.1.2 @ContextConfiguration注解

@ContextConfiguration定义类级元数据,用于确定如何为集成测试加载和配置ApplicationContext。具体地说,@ContextConfiguration声明应用程序上下文的资源位置和用于加载上下文中带注解的类。

资源位置通常是XML配置文件或者是在类路径中的Groovy脚本;注解类通常是@Configuration类。但是,资源位置也可以引用文件系统中的文件和脚本,而带注解的类可以是组件(component )类等等。

@ContextConfiguration("/test-config.xml")
public class XmlApplicationContextTests {
// class body...
}
 
@ContextConfiguration(classes = TestConfig.class)
public class ConfigClassApplicationContextTests {
// class body...
}

除了声明资源位置或注解类之外,还可以使用@ContextConfiguration来声明ApplicationContextInitializer类。

@ContextConfiguration(initializers =CustomContextIntializer.class)
public class ContextInitializerTests {
// class body...
}

你可能感兴趣的:(Spring)