使用 Spring Boot 1.4 的自定义测试切片

工程 | Stéphane Nicoll | 2016 年 8 月 30 日 | ...

Spring Boot 1.4 对测试支持进行了重大改进,其中一项特性就是 测试切片 (test slicing)。我想借这篇博客文章进一步解释它是什么以及如何轻松创建自己的测试切片。

测试切片旨在对为测试创建的 ApplicationContext 进行分段。通常,如果您想使用 MockMvc 测试一个控制器,肯定不想涉及数据层。相反,您可能希望 模拟 (mock) 控制器使用的服务,并验证所有与 Web 相关的交互是否按预期工作。这可以用下面的示例来概括

@RunWith(SpringRunner.class)
@WebMvcTest(UserVehicleController.class)
public class UserVehicleControllerTests {

    @Autowired
    private MockMvc mvc;

    @MockBean
    private UserVehicleService userVehicleService;

    @Test
    public void testExample() throws Exception {
        given(this.userVehicleService.getVehicleDetails("sboot"))
                .willReturn(new VehicleDetails("Honda", "Civic"));
        this.mvc.perform(get("/sboot/vehicle").accept(MediaType.TEXT_PLAIN))
                .andExpect(status().isOk()).andExpect(content().string("Honda Civic"));
    }

}

@WebMvcTest 是 Spring Boot 1.4 中的 Web 测试切片。当它存在时,您就指示 Spring Boot 需要一个 Web 环境,并且只应实例化指定的控制器。因为它了解测试的性质,所以可以为您做出额外的智能决策(例如,自动配置 MockMvc,您只需注入即可)。此外,您的控制器依赖于 UserVehicleService,因此启动上下文将导致失败,因为 ApplicationContext 不知道它(请记住,只知道 Web 基础设施和 UserVehicleController)。这里使用 @MockBean 来注册 UserVehicleService 的 Mock,以便可以透明地注入到控制器中。

现在让我们看看实现,以便更好地理解 Spring Boot 是如何为您管理这一切的。我们的第一站是 @WebMvcTest(为简洁起见,去掉了 @Target 及相关内容)

@BootstrapWith(WebMvcTestContextBootstrapper.class)
@OverrideAutoConfiguration(enabled = false)
@TypeExcludeFilters(WebMvcTypeExcludeFilter.class)
@AutoConfigureCache
@AutoConfigureWebMvc
@AutoConfigureMockMvc
@ImportAutoConfiguration
public @interface WebMvcTest { ... }

此声明可以分为 3 个区域

  • 自动配置定制
  • 类路径扫描调优
  • 测试引导

自动配置定制

Spring Boot 1.4 现在定义了一个 spring-boot-test-autoconfigure 模块,该模块提供了一系列与测试相关的自动配置。这些自动配置是可组合的,可以帮助您轻松构建自己的基础设施。

回到 @WebMvcTest,我们首先要做的是禁用默认的自动配置:OverrideAutoConfiguration 实现了这一点。由于默认自动配置已被禁用,您必须选择加入您希望包含的相关自动配置。三个 AutoConfigure 注解就是为我们做这件事的:它们确保 Web 环境可用,MockMvc 已配置,并且一个无操作的缓存管理器可用。让我们看看 AutoconfigureMockMvc 的一个片段

@ImportAutoConfiguration
@PropertyMapping("spring.test.mockmvc")
public @interface AutoConfigureMockMvc {

    boolean addFilters() default true;

    @PropertyMapping("webclient.enabled")
    boolean webClientEnabled() default true;

    ...
}

@ImportAutoConfiguration 是一个注解,它列出了应包含的自动配置。或者,您可以使用注解的完全限定名作为键,在 META-INF/spring.factories 中提供列表。这就是为 AutoConfigureMockMvc 定义的内容

org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc=\
org.s.boot.test.autoconfigure.web.servlet.MockMvcAutoConfiguration,\
org.s.boot.test.autoconfigure.web.servlet.MockMvcSecurityAutoConfiguration,\
org.s.boot.test.autoconfigure.web.servlet.MockMvcWebClientAutoConfiguration,\
org.s.boot.test.autoconfigure.web.servlet.MockMvcWebDriverAutoConfiguration

您明白了:每个注解都会带来一些自动配置,您可以随意组合它们。您会注意到 WebMvcTest 也有一个 ImportAutoConfiguration,但在 spring.factories 中没有对应的条目。Spring Boot 将扫描类路径中的所有 spring.factories,并在必要时 合并 内容。如果您的某个模块想为 @WebMvcTest(或 @AutoConfigureMockMvc)添加额外行为,只需创建一个 META-INF/spring.factories 并注册额外的自动配置类即可。您还可以使用 @AutoconfigureBefore@AutoconfigureAfter 来对它们进行排序。

测试自动配置像往常一样是可配置的:类级别的 @PropertyMapping 注解将注解的属性映射到 Environment,以便自动配置代码可以提取值并相应地调整配置。我们可以看到上面提到的 webClientEnabled 属性在自动配置中被透明地使用了

@ConditionalOnProperty(prefix = "spring.test.mockmvc.webclient", 
        name = "enabled", matchIfMissing = true)
public class MockMvcWebClientAutoConfiguration { ... }

类路径扫描调优

TypeExcludeFilters 是一种调优类路径扫描的方式。在 @WebMvcTest 的情况下,我们只会 包含某些与 Web 相关的组件 并忽略所有其余部分。这非常强大,因为您可以像往常一样使用类路径扫描,并且只包含您的切片所需的内容。

测试引导

最后,新的测试引导程序会确保识别您的项目中带有 @SpringBootApplication 注解的类(除非指定了其他类)。这是一个很好的默认设置,因为您不再需要指定它,并且类路径扫描将 默认 正确。

创建您自己的切片

基于这些知识,创建您自己的切片实际上非常容易。一个这样的切片示例可能是一个新的 DataJdbcTest,它是一个类似于 DataJpaTest 的切片,只配置 JdbcTemplate 而不使用 JPA。如果您想立即尝试代码,请查看 GitHub 仓库了解更多详情。

我们的第一步是创建 @AutoconfigureDataJdbc

package com.example.test.autoconfigure.jdbc;

import java.lang.annotation.*;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ImportAutoConfiguration
public @interface AutoconfigureDataJdbc {
}

并注册当此注解存在时要应用的相关的自动配置。同样,创建一个 META-INF/spring.factories 资源

com.example.test.autoconfigure.jdbc.AutoconfigureDataJdbc=\
org.s.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.s.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.s.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.s.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.s.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.s.boot.autoconfigure.transaction.TransactionAutoConfiguration

一旦可重用的基础设施就位,您就可以创建您的测试切片,并简单地指定您需要数据库和 JDBC

@BootstrapWith(SpringBootTestContextBootstrapper.class)
@OverrideAutoConfiguration(enabled = false)
@TypeExcludeFilters(DataJdbcTypeExcludeFilter.class)
@Transactional
@AutoConfigureCache
@AutoconfigureDataJdbc
@AutoConfigureTestDatabase
@ImportAutoConfiguration
public @interface DataJdbcTest { }

DataJdbcTypeExcludeFilter 确保排除所有其他服务,因为此类测试默认不应依赖于您的任何 Bean。可以改进它,允许将服务定义为注解的参数,就像 WebMvcTest 添加指定的控制器一样。

完成上述步骤后,您只需添加您的注解,您的 JdbcTemplate 就会为您自动配置一个测试数据库

@RunWith(SpringRunner.class)
@DataJdbcTest
public class DataJdbcSampleTests {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    ...
}

总结

Spring Boot 1.4 将自动配置引入到您的测试中,并允许您轻松组合您自己的测试注解。在本文中,我们了解了 WebMvcTest 的工作原理以及如何创建您自己的 “jdbc” 切片。我们实际上正在 考虑在下一个版本中添加该注解,所以请 继续提供反馈

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,助您加速进步。

了解更多

获得支持

Tanzu Spring 通过一个简单的订阅提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将到来的活动

查看 Spring 社区的所有即将到来的活动。

查看全部