1. 概述

在开发和部署过程中,为不同阶段创建不同配置是常见需求。部署Spring应用时,我们可以为每个阶段分配Spring环境配置,并编写专门的测试用例。

本教程将重点介绍如何使用JUnit 5根据活动的Spring环境配置执行测试。

2. 项目搭建

首先添加依赖项:

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
</dependency>

创建一个简单的Spring Boot应用:

@SpringBootApplication
public class ActiveProfileApplication {

    public static void main (String [] args){
        SpringApplication.run(Application.class);
    }
}

最后创建application.yaml作为默认属性源文件。

3. Spring环境配置

Spring环境配置通过分组特定环境的配置设置,提供定义和管理不同环境的方式。

激活特定配置文件后,我们可以轻松切换不同配置和设置。

3.1. 在属性文件中激活环境配置

application.yaml中指定活动环境配置:

spring:
  profiles:
    active: dev

Spring将加载活动环境配置的所有属性,并将专用bean注入应用上下文。

本教程中,我们将为每个环境配置创建专用属性文件。因为为每个配置文件创建专用文件能简化管理和更新特定环境配置的过程。

创建testprod两个环境配置,每个都包含profile.property.value属性,但值对应文件名不同:

创建application-prod.yaml

profile:
  property:
    value: This the the application-prod.yaml file

类似地创建application-test.yaml

profile:
  property:
    value: This the the application-test.yaml file

最后在application.yaml中添加相同属性:

profile:
  property:
    value: This the the application.yaml file

编写测试验证应用行为:

@SpringBootTest(classes = ActiveProfileApplication.class)
public class DevActiveProfileUnitTest {

    @Value("${profile.property.value}")
    private String propertyString;

    @Test
    void whenDevIsActive_thenValueShouldBeKeptFromApplicationYaml() {
        Assertions.assertEquals("This the the application.yaml file", propertyString);
    }
}

注入的propertyString值来自application.yaml,因为测试执行时激活的是dev环境配置,且该配置没有专用属性文件。

3.2. 在测试类中设置活动环境配置

通过设置spring.profiles.active属性可激活对应环境配置并加载关联文件。

但某些场景下,我们可能希望用特定配置执行测试类,覆盖属性文件中定义的活动配置。

**此时可使用@ActiveProfiles注解(与JUnit 5兼容),它声明了为测试类加载应用上下文时使用的活动环境配置。

若在测试类上添加@ActiveProfiles注解并设置value属性为test,该类所有测试都将使用test配置:

@SpringBootTest(classes = ActiveProfileApplication.class)
@ActiveProfiles(value = "test")
public class TestActiveProfileUnitTest {

    @Value("${profile.property.value}")
    private String propertyString;

    @Test
    void whenTestIsActive_thenValueShouldBeKeptFromApplicationTestYaml() {
        Assertions.assertEquals("This the the application-test.yaml file", propertyString);
    }
}

value属性(profiles属性的别名)是字符串数组。因为可以通过逗号分隔列表指定多个活动环境配置。

例如同时激活testprod

@ActiveProfiles({"prod", "test"})

应用上下文将使用testprod配置的特定属性和配置。

配置按列表顺序应用,不同配置间冲突时,后列出的配置优先级更高。

基于活动环境配置执行测试对确保应用在不同环境正确运行至关重要。但在其他环境执行特定配置的测试存在风险——例如在本地机器上运行时可能意外触发生产环境测试。

为避免此情况,需要找到根据活动环境配置过滤测试执行的方法。

4. @EnabledIf注解

JUnit 4中可通过@IfProfileValue注解条件执行测试。但当使用JUnit 5时,应避免使用@IfProfileValue,因其当前版本已不再支持。

替代方案是使用@EnabledIf注解,该注解基于条件启用或禁用方法/类。

JUnit 5也提供@EnabledIf注解。需确保导入Spring提供的版本避免混淆。

该注解包含以下属性:

  • value:启用测试类/方法的条件表达式(需为true
  • expression:同样指定条件表达式(标记为@AliasFor
  • loadContext:是否需加载上下文评估条件(默认false
  • reason:条件需求的说明

评估使用Spring应用上下文值的条件(如活动环境配置)时,应将loadContext设为true

4.1. 为单个环境配置执行测试

若仅当特定环境配置激活时运行测试类,可用SPEL函数评估value属性:

#{environment.getActiveProfiles()[0] == 'prod'}

此函数中:

  • environment变量实现Environment接口
  • environment.getActiveProfiles()返回当前环境的活动配置数组
  • [0]访问数组第一个元素

添加注解到测试类:

@SpringBootTest(classes = ActiveProfileApplication.class)
@EnabledIf(value = "#{environment.getActiveProfiles()[0] == 'prod'}", loadContext = true)
public class ProdActiveProfileUnitTest {

    @Value("${profile.property.value}")
    private String propertyString;

    @Test
    void whenProdIsActive_thenValueShouldBeKeptFromApplicationProdYaml() {
        Assertions.assertEquals("This the the application-prod.yaml file", propertyString);
    }
}

再通过@ActiveProfiles激活prod配置:

@SpringBootTest(classes = ActiveProfileApplication.class)
@EnabledIf(value = "#{environment.getActiveProfiles()[0] == 'prod'}", loadContext = true)
@ActiveProfiles(value = "prod")
public class ProdActiveProfileUnitTest {

    @Value("${profile.property.value}")
    private String propertyString;

    @Test
    void whenProdIsActive_thenValueShouldBeKeptFromApplicationProdYaml() {
        Assertions.assertEquals("This the the application-prod.yaml file", propertyString);
    }
}

此时测试类将始终使用prod配置执行,且仅当当前配置确实为prod时运行。

4.2. 为多个环境配置执行测试

若要在不同活动配置下执行测试,可用SPEL函数评估valueexpression属性:

#{{'test', 'prod'}.contains(environment.getActiveProfiles()[0])}

函数解析:

  • {'test','prod'}定义包含两个配置名的集合
  • .contains(environment.getActiveProfiles()[0])检查数组首元素是否在集合中

添加@EnableIf注解到测试类:

@SpringBootTest(classes = ActiveProfileApplication.class)
@EnabledIf(value = "#{{'test', 'prod'}.contains(environment.getActiveProfiles()[0])}", loadContext = true)
@ActiveProfiles(value = "test")
public class MultipleActiveProfileUnitTest {
    @Value("${profile.property.value}")
    private String propertyString;

    @Autowired
    private Environment env;

    @Test
    void whenDevIsActive_thenValueShouldBeKeptFromDedicatedApplicationYaml() {
        String currentProfile = env.getActiveProfiles()[0];
        Assertions.assertEquals(String.format("This the the application-%s.yaml file", currentProfile), propertyString);
    }
}

测试类将在活动配置为testprod时运行。

5. 总结

本文介绍了如何使用JUnit 5注解基于活动Spring环境配置执行测试。我们学习了如何在测试类中启用环境配置,以及如何在一个或多个特定配置激活时执行测试。

完整示例代码可在GitHub获取。


原始标题:Execute Tests Based on Active Profile With JUnit 5 | Baeldung