1. 概述
在本教程中,我们将会探讨在 Spring 测试中覆盖配置属性的几种常见方式。
Spring 提供了多种机制来让我们在测试环境中灵活地修改配置属性值,适用于不同场景下的测试需求。
2. 依赖准备
要进行 Spring 测试,首先需要引入测试依赖。通常我们会使用 Spring Boot 提供的 starter test:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
这个依赖会自动引入 JUnit 5、Mockito、Spring Test 等测试相关库。
3. 示例类准备
为了演示属性覆盖效果,我们先定义一个简单的组件类:
@Component
public class PropertySourceResolver {
@Value("${example.firstProperty}") private String firstProperty;
@Value("${example.secondProperty}") private String secondProperty;
public String getFirstProperty() {
return firstProperty;
}
public String getSecondProperty() {
return secondProperty;
}
}
然后在 src/main/resources/application.properties
中定义默认属性:
example.firstProperty=defaultFirst
example.secondProperty=defaultSecond
4. 通过测试资源文件覆盖属性
这是最直接的一种方式:在测试资源目录下创建同名的 application.properties
文件,Spring 会自动使用它来覆盖主资源目录下的配置。
在 src/test/resources/application.properties
中添加:
example.firstProperty=file
example.secondProperty=file
编写测试类验证属性是否被覆盖:
@SpringBootTest
public class TestResourcePropertySourceResolverIntegrationTest {
@Autowired private PropertySourceResolver propertySourceResolver;
@Test
public void shouldTestResourceFile_overridePropertyValues() {
String firstProperty = propertySourceResolver.getFirstProperty();
String secondProperty = propertySourceResolver.getSecondProperty();
assertEquals("file", firstProperty);
assertEquals("file", secondProperty);
}
}
✅ 优点:简单直接,适用于覆盖多个属性。
⚠️ 注意:必须包含所有属性 key,否则未定义的属性将不会生效。
5. 使用 Spring Profiles
Spring Profiles 是另一种常见做法,它允许我们定义 profile-specific 的配置文件,并在测试中激活特定 profile。
在 src/test/resources/application-test.properties
中添加:
example.firstProperty=profile
测试类中通过 @ActiveProfiles
激活 profile:
@SpringBootTest
@ActiveProfiles("test")
public class ProfilePropertySourceResolverIntegrationTest {
@Autowired private PropertySourceResolver propertySourceResolver;
@Test
public void shouldProfiledProperty_overridePropertyValues() {
String firstProperty = propertySourceResolver.getFirstProperty();
String secondProperty = propertySourceResolver.getSecondProperty();
assertEquals("profile", firstProperty);
assertEquals("defaultSecond", secondProperty);
}
}
✅ 优点:
- 可以合并默认配置与 profile 配置
- 适合多环境配置管理
⚠️ 注意:profile 文件名格式必须为 application-{profile}.properties
。
6. 使用 @SpringBootTest
的 properties 属性
如果你只想覆盖几个特定的属性,可以使用 @SpringBootTest
的 properties
参数,直接在注解中指定:
@SpringBootTest(properties = { "example.firstProperty=annotation" })
public class SpringBootPropertySourceResolverIntegrationTest {
@Autowired private PropertySourceResolver propertySourceResolver;
@Test
public void shouldSpringBootTestAnnotation_overridePropertyValues() {
String firstProperty = propertySourceResolver.getFirstProperty();
String secondProperty = propertySourceResolver.getSecondProperty();
Assert.assertEquals("annotation", firstProperty);
Assert.assertEquals("defaultSecond", secondProperty);
}
}
✅ 优点:
- 非常直观,适合单个或少量属性覆盖
- 不需要额外配置文件
❌ 缺点:只能在 Spring Boot 项目中使用。
7. 使用 TestPropertySourceUtils
Spring 提供了一个工具类 TestPropertySourceUtils
,可以在 ApplicationContextInitializer
中动态添加属性。
先定义一个初始化类:
public class PropertyOverrideContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
static final String PROPERTY_FIRST_VALUE = "contextClass";
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
configurableApplicationContext, "example.firstProperty=" + PROPERTY_FIRST_VALUE);
TestPropertySourceUtils.addPropertiesFilesToEnvironment(
configurableApplicationContext, "context-override-application.properties");
}
}
然后在 src/test/resources/context-override-application.properties
中添加:
example.secondProperty=contextFile
最后编写测试类:
@SpringBootTest
@ContextConfiguration(
initializers = PropertyOverrideContextInitializer.class,
classes = Application.class)
public class ContextPropertySourceResolverIntegrationTest {
@Autowired private PropertySourceResolver propertySourceResolver;
@Test
public void shouldContext_overridePropertyValues() {
final String firstProperty = propertySourceResolver.getFirstProperty();
final String secondProperty = propertySourceResolver.getSecondProperty();
assertEquals(PropertyOverrideContextInitializer.PROPERTY_FIRST_VALUE, firstProperty);
assertEquals("contextFile", secondProperty);
}
}
✅ 优点:
- 灵活性高,支持内联属性和文件属性混合
- 适用于需要在上下文初始化阶段动态配置的场景
8. 总结
方法 | 适用场景 | 是否需要 Spring Boot | 是否需要额外文件 |
---|---|---|---|
测试资源文件覆盖 | 覆盖多个属性 | ❌ | ✅ |
Spring Profiles | 合并默认与测试配置 | ❌ | ✅ |
@SpringBootTest#properties |
覆盖少量属性 | ✅ | ❌ |
TestPropertySourceUtils |
动态添加属性 | ❌ | ✅/❌ |
根据你的测试需求选择合适的属性覆盖方式,可以更高效地完成集成测试或单元测试。
如需查看完整示例代码,可访问 GitHub 仓库。