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 属性

如果你只想覆盖几个特定的属性,可以使用 @SpringBootTestproperties 参数,直接在注解中指定:

@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 仓库


原始标题:Override Properties in Spring's Tests | Baeldung