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注入应用上下文。
本教程中,我们将为每个环境配置创建专用属性文件。因为为每个配置文件创建专用文件能简化管理和更新特定环境配置的过程。
创建test
和prod
两个环境配置,每个都包含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
属性的别名)是字符串数组。因为可以通过逗号分隔列表指定多个活动环境配置。
例如同时激活test
和prod
:
@ActiveProfiles({"prod", "test"})
应用上下文将使用test
和prod
配置的特定属性和配置。
配置按列表顺序应用,不同配置间冲突时,后列出的配置优先级更高。
基于活动环境配置执行测试对确保应用在不同环境正确运行至关重要。但在其他环境执行特定配置的测试存在风险——例如在本地机器上运行时可能意外触发生产环境测试。
为避免此情况,需要找到根据活动环境配置过滤测试执行的方法。
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函数评估value
或expression
属性:
#{{'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);
}
}
测试类将在活动配置为test
或prod
时运行。
5. 总结
本文介绍了如何使用JUnit 5注解基于活动Spring环境配置执行测试。我们学习了如何在测试类中启用环境配置,以及如何在一个或多个特定配置激活时执行测试。
完整示例代码可在GitHub获取。