如何在 Spring 测试中设置环境变量或系统属性?
Posted
技术标签:
【中文标题】如何在 Spring 测试中设置环境变量或系统属性?【英文标题】:How to set environment variable or system property in spring tests? 【发布时间】:2012-07-03 15:37:38 【问题描述】:我想编写一些测试来检查已部署 WAR 的 XML Spring 配置。不幸的是,有些 bean 需要设置一些环境变量或系统属性。使用@ContextConfiguration方便的测试样式时,如何在spring bean初始化之前设置环境变量?
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:whereever/context.xml")
public class TestWarSpringContext ...
如果我使用注释配置应用程序上下文,我看不到在 spring 上下文初始化之前我可以做某事的钩子。
【问题讨论】:
【参考方案1】:您可以在静态初始化程序中初始化 System 属性:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:whereever/context.xml")
public class TestWarSpringContext
static
System.setProperty("myproperty", "foo");
静态初始化代码将在spring应用上下文初始化之前执行。
【讨论】:
傻我 - 好吧,那会工作。更好的是:可能设置系统属性的@BeforeClass
方法和删除它的@AfterClass
方法也可以工作,并且可以很好地自行清理。 (不过没试过。)
尝试了@BeforeClass - 在测试实例中设置其他属性之前,它可以很好地设置系统属性
谢谢。静态的东西没有用,但是@BeforeClass 的一个小方法起作用了!
如果更改 Log4j2 配置文件属性,此机制将不起作用。似乎无论如何都在该静态代码之前加载了Spring(因此记录不正确)。
这样,系统属性在spring应用上下文初始化之前被初始化一次。测试需要更改系统属性值的方法看起来如何?例如,测试 A 要求 myproperty
的值是 foo
,但测试 B 要求 myproperty
的值是 somethingelse
。【参考方案2】:
从 Spring 4.1 开始,正确的做法是使用 @TestPropertySource
注释。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:whereever/context.xml")
@TestPropertySource(properties = "myproperty = foo")
public class TestWarSpringContext
...
参见Spring docs 和Javadocs 中的@TestPropertySource。
【讨论】:
这个注解也支持属性文件路径。 我可以在测试期间使用@TestPropertySource(properties="spring.cloud.config.label=feature/branch")
切换 Spring Cloud Config Client 标签
很好的答案,但遗憾的是对我不起作用,使用 Spring 4.2.9,属性总是空的。只有静态块有效...适用于应用程序属性,但不适用于系统属性。
首先我看到并尝试了静态版本(它有效),但这个注释更干净,更可取(对我来说,因为它也像一个魅力)。
这提供了一个Environment
属性,它不同于“环境变量”。【参考方案3】:
也可以使用测试 ApplicationContextInitializer 来初始化系统属性:
public class TestApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>
@Override
public void initialize(ConfigurableApplicationContext applicationContext)
System.setProperty("myproperty", "value");
然后在测试类上配置它除了Spring上下文配置文件位置:
@ContextConfiguration(initializers = TestApplicationContextInitializer.class, locations = "classpath:whereever/context.xml", ...)
@RunWith(SpringJUnit4ClassRunner.class)
public class SomeTest
...
如果应该为所有单元测试设置某个系统属性,这样可以避免代码重复。
【讨论】:
这也适用于 Spring Boot 2.x 和 Junit 5.x(使用@SpringBootTest
或任何 test slicing 注释)【参考方案4】:
目前这里的所有答案都只讨论与设置更复杂的环境变量不同的系统属性,尤其是。用于测试。值得庆幸的是,可以使用下面的类,并且类文档有很好的例子
EnvironmentVariables.html
文档中的一个简单示例,已修改为使用 @SpringBootTest
@SpringBootTest
public class EnvironmentVariablesTest
@ClassRule
public final EnvironmentVariables environmentVariables = new EnvironmentVariables().set("name", "value");
@Test
public void test()
assertEquals("value", System.getenv("name"));
【讨论】:
EnvironmentVariables 规则是第三方库的一部分,使用 hacky 反射来更改 JVM 内存中缓存的环境值,甚至不会更改实际的环境变量。所以,我不想使用它或推荐任何人这样做。 它似乎也有一个 ProvideSystemProperty 规则,奇怪的是,还有一个 RestoreSystemProperties 规则。所以这也适用于系统属性。【参考方案5】:如果您希望您的变量对所有测试都有效,您可以在您的测试资源目录中有一个application.properties
文件(默认情况下:src/test/resources
),它看起来像这样:
MYPROPERTY=foo
这将被加载和使用,除非您通过 @TestPropertySource
或类似方法定义 - 加载属性的确切顺序可以在 Spring 文档章节 24. Externalized Configuration 中找到。
【讨论】:
【参考方案6】:您可以将系统属性设置为 VM 参数。
如果您的项目是 maven 项目,那么您可以在运行测试类时执行以下命令:
mvn test -Dapp.url="https://***.com"
测试类:
public class AppTest
@Test
public void testUrl()
System.out.println(System.getProperty("app.url"));
如果你想在 Eclipse 中运行单独的测试类或方法:
1) 转到运行 -> 运行配置
2) 在左侧的 Junit 部分下选择您的测试类。
3) 执行以下操作:
【讨论】:
【参考方案7】:对于单元测试,系统变量在我执行“mvn clean install”时尚未实例化,因为没有服务器运行应用程序。所以为了设置系统属性,我需要在 pom.xml 中进行。像这样:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.21.0</version>
<configuration>
<systemPropertyVariables>
<propertyName>propertyValue</propertyName>
<MY_ENV_VAR>newValue</MY_ENV_VAR>
<ENV_TARGET>olqa</ENV_TARGET>
<buildDirectory>$project.build.directory</buildDirectory>
</systemPropertyVariables>
</configuration>
</plugin>
【讨论】:
【参考方案8】:对于springboot,我认为这是最简单的方法,可以在java中使用@SpringBootTest
注解:
@SpringBootTest(
properties = "spring.application.name=example", "ENV_VARIABLE=secret"
)
public class ApplicationTest
// Write your tests here
或者在 kotlin 中你可以这样做:
@SpringBootTest(
properties = ["spring.application.name=example", "ENV_VARIABLE=secret"]
)
internal class ApplicationKTest
// Write your tests here
就是这样,您的测试应该使用您在注释中定义的属性覆盖属性。
假设您的application.yml
看起来像这样:
spring:
application:
name: "app"
db:
username: "user"
password: $ENV_VARIABLE:default
那么在测试期间它将是:
spring 属性spring.application.name
将返回值"example"
环境变量ENV_VARIABLE
将返回"secret"
,因此如果您在代码中使用值db.password
,它将返回"secret"
。
【讨论】:
【参考方案9】:如果您有很多测试类(启动 tomcat/server 的 IT 测试),并且测试失败,您需要使用设置系统属性 System.setProperty("ccm.configs.dir", configPath); 由于您需要确保在 spring 开始之前设置它,因此您需要将它放在类中的静态上下文中。 并确保任何可能依赖于它的测试都获得此设置的系统属性,请在您的测试文件夹中定义一个简单的配置类来设置该变量。 PS在我的情况下,所需的环境变量是“ccm.configs.dir” 这是我在测试文件夹中添加的内容,
@Configuration
public class ConfigLoader
static
System.setProperty("ccm.configs.dir", "path/to/the/resource");
我所有的集成测试类都能够在它们运行时获取已经设置的变量。
【讨论】:
以上是关于如何在 Spring 测试中设置环境变量或系统属性?的主要内容,如果未能解决你的问题,请参考以下文章
在 gradle-pitest-plugin 中设置环境变量
如何在 Visual Studio 2010 中设置环境变量?