在集成测试中覆盖@Value

时间:2017-06-19 21:03:55

标签: java spring integration-testing spring-test

对于我的一个Spring bean(比如Application类),我使用@Value注释从属性文件(prop.properties)中获取属性的值(my.property.flag = true / false) 。这完全没问题。

我需要编写一个集成测试(比如说ApplicationIt类),我需要测试该属性的值,即true和false。

在我的属性文件中,属性的值设置为true。是否可以从我的Integration测试中将值动态设置为false?

例如,

prop.properties:

    my.property.flag=true

应用程序类文件:

    @Component
    class Application {
        //This value is fetched from properties file
        //the value is set to true.
        @Value(${my.property.flag})
        private String isTrue;
        ......
        ..........
    }

整合测试:

    class ApplicationIT {
        //how can I set the value of isTrue here to false?
    }

4 个答案:

答案 0 :(得分:8)

您可以在测试类上指定测试属性,如下所示:

@RunWith(SpringRunner.class)
@TestPropertySource(properties = {"spring.main.banner-mode=off", "my.property.flag=false"})
public class MyTest {

由于Spring具有完整的属性覆盖层次结构,因此非常有效,缺点是您需要针对不同值的单独测试类。如果您正在使用Spring Boot,那么另一个注释可提供相同的功能,但也有更多选项可用于配置您的测试环境。例如:

@SpringBootTest(properties = {"spring.main.banner-mode=off", "my.property.flag=false"})

同样,您将需要单独的测试类来处理硬编码的测试属性。

答案 1 :(得分:5)

我被这个问题搞砸了一段时间,发现这种方法可以覆盖属性。如果您需要对应用程序上下文进行某些编程初始化(例如注册属性源,而不仅仅是这种情况),那么它非常有用。以下方法使用ContextConfiguration' s initializers

Spring Boot 1.5.x 的示例:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {"management.port=0"})
@ContextConfiguration(initializers = AbstractIntegrationTest.Initializer.class)
@DirtiesContext
public abstract class AbstractIntegrationTest {

    private static int REDIS_PORT = 6379;

    @ClassRule
    public static GenericContainer redis = new GenericContainer("redis:3.0.6").withExposedPorts(REDIS_PORT);

    public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        @Override
        public void initialize(ConfigurableApplicationContext ctx) {
            TestPropertySourceUtils.addInlinedPropertiesToEnvironment(ctx,
                "spring.redis.host=" + redis.getContainerIpAddress(),
                "spring.redis.port=" + redis.getMappedPort(REDIS_PORT));
        }
    }
}

Spring Boot 2.x 的示例:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {"management.port=0"})
@ContextConfiguration(initializers = AbstractIntegrationTest.Initializer.class)
@DirtiesContext
public abstract class AbstractIntegrationTest {

    private static int REDIS_PORT = 6379;

    @ClassRule
    public static GenericContainer redis = new GenericContainer("redis:3.0.6").withExposedPorts(REDIS_PORT);

    public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        @Override
        public void initialize(ConfigurableApplicationContext ctx) {
            TestPropertyValues.of(
                "spring.redis.host:" + redis.getContainerIpAddress(),
                "spring.redis.port:" + redis.getMappedPort(REDIS_PORT))
                .applyTo(ctx);
        }
    }
}

答案 2 :(得分:3)

我想提一下旧的反思方式。在组件中连接后,可以使用spring提供的实用程序类:

ReflectionTestUtils.setField(component, "isTrue", true)

您可以在随后的测试中将其更改为您想要的任何值

答案 3 :(得分:1)

最好使用构造函数注入而不是场注入:

@Component
class Application {

    Application(@Value("${my.property.flag}") boolean flag) {
        ...
    }
}

这使得使用模拟或测试值就像传递参数一样简单。