Integration Testing

能够执行一些集成测试而不必部署到应用程序服务器或连接到其他企业基础架构非常重要。这样做可以让你测试如下事项:

It is important to be able to perform some integration testing without requiring deployment to your application server or connecting to other enterprise infrastructure. Doing so lets you test things such as:

  • The correct wiring of your Spring IoC container contexts.

  • Data access using JDBC or an ORM tool. This can include such things as the correctness of SQL statements, Hibernate queries, JPA entity mappings, and so forth.

Spring Framework 在 spring-test 模块中为集成测试提供了一流的支持。实际 JAR 文件的名称可能包含版本号,也可能采用较长的 org.springframework.test 形式,具体取决于您在哪里获得它(有关说明,请参阅 section on Dependency Management )。此库包含 org.springframework.test 软件包,其中包含用于使用 Spring 容器进行集成测试的有价值的类。此测试不依赖于应用程序服务器或其他部署环境。此类测试的运行速度比单元测试慢,但比依赖于部署到应用程序服务器的 Selenium 测试或远程测试快得多。

The Spring Framework provides first-class support for integration testing in the spring-test module. The name of the actual JAR file might include the release version and might also be in the long org.springframework.test form, depending on where you get it from (see the section on Dependency Management for an explanation). This library includes the org.springframework.test package, which contains valuable classes for integration testing with a Spring container. This testing does not rely on an application server or other deployment environment. Such tests are slower to run than unit tests but much faster than the equivalent Selenium tests or remote tests that rely on deployment to an application server.

单元和集成测试支持以基于注释的 Spring TestContext Framework 的形式提供。TestContext 框架与实际使用的测试框架无关,这允许在各种环境中对测试进行检测,包括 JUnit、TestNG 和其他环境。

Unit and integration testing support is provided in the form of the annotation-driven Spring TestContext Framework. The TestContext framework is agnostic of the actual testing framework in use, which allows instrumentation of tests in various environments, including JUnit, TestNG, and others.

以下部分概述了 Spring 集成支持的高级目标,本章的其余部分重点介绍专门的主题:

The following section provides an overview of the high-level goals of Spring’s integration support, and the rest of this chapter then focuses on dedicated topics:

Goals of Integration Testing

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

Spring’s integration testing support has the following primary goals:

以下部分介绍了每个目标,并提供了实现和配置详细信息的链接。

The next few sections describe each goal and provide links to implementation and configuration details.

Context Management and Caching

Spring TestContext Framework 提供一致加载 Spring ApplicationContext 实例和 WebApplicationContext 实例以及缓存这些上下文。对加载的上下文提供缓存支持非常重要,因为启动时间可能会成为问题——这并不是因为 Spring 本身开销太大,而是因为 Spring 容器实例化的对象需要时间来实例化。例如,一个包含 50 到 100 个 Hibernate 映射文件项目可能需要 10 到 20 秒来加载映射文件,每个测试夹具中运行每个测试之前都会产生该成本,从而导致整体测试运行速度变慢,降低开发人员的生产率。

The Spring TestContext Framework provides consistent loading of Spring ApplicationContext instances and WebApplicationContext instances as well as caching of those contexts. Support for the caching of loaded contexts is important, because startup time can become an issue — not because of the overhead of Spring itself, but because the objects instantiated by the Spring container take time to instantiate. For example, a project with 50 to 100 Hibernate mapping files might take 10 to 20 seconds to load the mapping files, and incurring that cost before running every test in every test fixture leads to slower overall test runs that reduce developer productivity.

测试类通常会声明 XML 或 Groovyconfiguration 元数据(通常在类路径中)的资源位置数组,或用于配置应用程序的组件类数组。这些位置或类与 web.xml 或生产部署的其他配置文件中指定的位置或类相同或相似。

Test classes typically declare either an array of resource locations for XML or Groovy configuration metadata — often in the classpath — or an array of component classes that is used to configure the application. These locations or classes are the same as or similar to those specified in web.xml or other configuration files for production deployments.

在默认情况下,配置的 ApplicationContext 在加载后可用于每次测试。因此,每个测试套件只产生一次安装费用,随后的测试执行速度会快很多。在此上下文中,“测试套件”一词表示在同一 JVM 中运行的所有测试,例如,给定项目模块针对 Ant、Maven 或 Gradle 进行构建时运行的所有测试。在不太可能的情况下,如果某个测试破坏了应用程序上下文并需要重新加载(例如,修改 Bean 定义或应用程序对象的状况),则可以将 TestContext 框架配置为在执行下一个测试之前重新加载配置并重建应用程序上下文。

By default, once loaded, the configured ApplicationContext is reused for each test. Thus, the setup cost is incurred only once per test suite, and subsequent test execution is much faster. In this context, the term “test suite” means all tests run in the same JVM — for example, all tests run from an Ant, Maven, or Gradle build for a given project or module. In the unlikely case that a test corrupts the application context and requires reloading (for example, by modifying a bean definition or the state of an application object) the TestContext framework can be configured to reload the configuration and rebuild the application context before executing the next test.

使用 TestContext 框架,请参阅 Context ManagementContext Caching

See Context Management and Context Caching with the TestContext framework.

Dependency Injection of Test Fixtures

当 TestContext 框架加载您的应用程序上下文时,它可以借助依赖注入功能选择性地配置测试类实例。这提供了一种便捷机制,可使用应用程序上下文中的预置 Bean 来设置测试夹具。这其中有一个很大的好处是,您可以在各种测试场景中重新利用应用程序上下文(例如,配置 Spring 管理的对象图、事务代理、DataSource 实例等),从而避免为个别测试用例复制复杂的测试夹具安装。

When the TestContext framework loads your application context, it can optionally configure instances of your test classes by using Dependency Injection. This provides a convenient mechanism for setting up test fixtures by using preconfigured beans from your application context. A strong benefit here is that you can reuse application contexts across various testing scenarios (for example, for configuring Spring-managed object graphs, transactional proxies, DataSource instances, and others), thus avoiding the need to duplicate complex test fixture setup for individual test cases.

例如,假设有一个类 (HibernateTitleRepository),用于实现 Title 域实体的数据访问逻辑。我们希望编写集成测试来测试以下区域:

As an example, consider a scenario where we have a class (HibernateTitleRepository) that implements data access logic for a Title domain entity. We want to write integration tests that test the following areas:

  • The Spring configuration: Basically, is everything related to the configuration of the HibernateTitleRepository bean correct and present?

  • The Hibernate mapping file configuration: Is everything mapped correctly and are the correct lazy-loading settings in place?

  • The logic of the HibernateTitleRepository: Does the configured instance of this class perform as anticipated?

使用 TestContext framework 查看测试 fixture 的依赖注入。

See dependency injection of test fixtures with the TestContext framework.

Transaction Management

在访问真实数据库的测试中,一个常见问题是它们对持久性存储状态的影响。即使在使用开发数据库时,对状态的更改也可能会影响后续测试。此外,许多操作(例如插入或修改持久性数据)无法在事务外部执行(或验证)。

One common issue in tests that access a real database is their effect on the state of the persistence store. Even when you use a development database, changes to the state may affect future tests. Also, many operations — such as inserting or modifying persistent data — cannot be performed (or verified) outside of a transaction.

TestContext 框架解决了这个问题。在默认情况下,该框架会为每个测试创建并回滚一个事务。您可以编写可以假定存在事务的代码。如果您在测试中调用事务代理对象,则它们会根据事务语义配置正确运行。此外,如果某个测试方法在为测试管理的事务中运行时删除了特定表的内容,则该事务会在默认情况下回滚,并且会在执行测试前数据库返回到其原有状态。事务支持会通过使用测试的应用程序上下文中定义的 PlatformTransactionManager Bean 来提供给测试。

The TestContext framework addresses this issue. By default, the framework creates and rolls back a transaction for each test. You can write code that can assume the existence of a transaction. If you call transactionally proxied objects in your tests, they behave correctly, according to their configured transactional semantics. In addition, if a test method deletes the contents of selected tables while running within the transaction managed for the test, the transaction rolls back by default, and the database returns to its state prior to execution of the test. Transactional support is provided to a test by using a PlatformTransactionManager bean defined in the test’s application context.

如果您希望提交事务(这并不常见,但当您希望特定测试填充或修改数据库时偶尔会很有用),您可以通过使用 @Commit 注释告诉 TestContext 框架提交事务,而不是回滚事务。

If you want a transaction to commit (unusual, but occasionally useful when you want a particular test to populate or modify the database), you can tell the TestContext framework to cause the transaction to commit instead of roll back by using the @Commit annotation.

使用 TestContext framework 查看事务管理。

See transaction management with the TestContext framework.

Support Classes for Integration Testing

Spring TestContext 框架提供了几个 abstract 支持类,可简化集成测试的编写。这些基本测试类提供了进入测试框架的明确挂钩以及方便的实例变量和方法,可让您访问:

The Spring TestContext Framework provides several abstract support classes that simplify the writing of integration tests. These base test classes provide well-defined hooks into the testing framework as well as convenient instance variables and methods, which let you access:

  • The ApplicationContext, for performing explicit bean lookups or testing the state of the context as a whole.

  • A JdbcTemplate, for executing SQL statements to query the database. You can use such queries to confirm database state both before and after execution of database-related application code, and Spring ensures that such queries run in the scope of the same transaction as the application code. When used in conjunction with an ORM tool, be sure to avoid false positives.

此外,您可能还希望创建自己的自定义应用范围超类的实例变量和方法,这些变量和方法特定于您的项目。

In addition, you may want to create your own custom, application-wide superclass with instance variables and methods specific to your project.

查看 TestContext framework 的支持类。

See support classes for the TestContext framework.