在集成测试中重写@Value
Overriding @Value in Integration Test
对于我的一个 Spring beans(比如应用程序 class),我正在获取 属性(my.property.flag=true/false 的值) 使用 @Value 注释从属性文件 (prop.properties) 中获取。效果很好。
我需要编写一个集成测试(比如 ApplicationIt class),我需要用 属性 的两个值进行测试,即 true 和 false。
在我的属性文件中,属性 的值设置为 true。是否可以从我的集成测试中将值动态设置为 false?
例如,
prop.properties:
my.property.flag=true
申请class文件:
@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?
}
您可以在测试 class 上指定测试属性,如下所示:
@RunWith(SpringRunner.class)
@TestPropertySource(properties = {"spring.main.banner-mode=off", "my.property.flag=false"})
public class MyTest {
由于 Spring 具有整个 属性 覆盖层次结构,因此效果很好,缺点是您需要针对不同的值单独测试 classes。如果您使用的是 Spring Boot,则还有另一个注释提供相同的功能,但也有更多的选项来配置您的测试环境。示例:
@SpringBootTest(properties = {"spring.main.banner-mode=off", "my.property.flag=false"})
同样,您将需要单独的测试 classes 来处理硬编码测试属性。
最好使用构造函数注入而不是字段注入:
@Component
class Application {
Application(@Value("${my.property.flag}") boolean flag) {
...
}
}
这使得使用模拟或测试值就像传递参数一样简单。
我想提一下很好的旧反射方式。在连接组件后,您可以使用 spring 提供的实用程序 class:
ReflectionTestUtils.setField(component, "isTrue", true)
您可以在后续测试中将其更改为您想要的任何值
我被这个困扰了一段时间,发现了这种覆盖属性的巧妙方法。如果您需要对应用程序上下文进行一些编程初始化,例如在这种情况下注册 属性 源,这将非常有用,但不仅限于此。以下方法使用 ContextConfiguration
的 initializers
。
Spring 引导 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 启动示例 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);
}
}
}
对于我的一个 Spring beans(比如应用程序 class),我正在获取 属性(my.property.flag=true/false 的值) 使用 @Value 注释从属性文件 (prop.properties) 中获取。效果很好。
我需要编写一个集成测试(比如 ApplicationIt class),我需要用 属性 的两个值进行测试,即 true 和 false。
在我的属性文件中,属性 的值设置为 true。是否可以从我的集成测试中将值动态设置为 false?
例如,
prop.properties:
my.property.flag=true
申请class文件:
@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?
}
您可以在测试 class 上指定测试属性,如下所示:
@RunWith(SpringRunner.class)
@TestPropertySource(properties = {"spring.main.banner-mode=off", "my.property.flag=false"})
public class MyTest {
由于 Spring 具有整个 属性 覆盖层次结构,因此效果很好,缺点是您需要针对不同的值单独测试 classes。如果您使用的是 Spring Boot,则还有另一个注释提供相同的功能,但也有更多的选项来配置您的测试环境。示例:
@SpringBootTest(properties = {"spring.main.banner-mode=off", "my.property.flag=false"})
同样,您将需要单独的测试 classes 来处理硬编码测试属性。
最好使用构造函数注入而不是字段注入:
@Component
class Application {
Application(@Value("${my.property.flag}") boolean flag) {
...
}
}
这使得使用模拟或测试值就像传递参数一样简单。
我想提一下很好的旧反射方式。在连接组件后,您可以使用 spring 提供的实用程序 class:
ReflectionTestUtils.setField(component, "isTrue", true)
您可以在后续测试中将其更改为您想要的任何值
我被这个困扰了一段时间,发现了这种覆盖属性的巧妙方法。如果您需要对应用程序上下文进行一些编程初始化,例如在这种情况下注册 属性 源,这将非常有用,但不仅限于此。以下方法使用 ContextConfiguration
的 initializers
。
Spring 引导 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 启动示例 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);
}
}
}