如何在弹簧测试中设定环境变量或系统属性?

我想编写一些测试来检查已部署的 WAR 的 XMLSpring 配置。不幸的是,有些 bean 需要设置一些环境变量或系统属性。使用@ContextConfiguration 方便的测试样式,如何在初始化 Spring bean 之前设置环境变量?

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:whereever/context.xml")
public class TestWarSpringContext { ... }

如果我使用注释配置应用程序上下文,那么在初始化 Spring 上下文之前,我看不到可以执行任何操作的挂钩。

235767 次浏览

可以在静态初始值设定项中初始化 System 属性:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:whereever/context.xml")
public class TestWarSpringContext {


static {
System.setProperty("myproperty", "foo");
}


}

The static initializer code will be executed before the spring application context is initialized.

从 Spring 4.1开始,正确的做法是使用 @TestPropertySource注释。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:whereever/context.xml")
@TestPropertySource(properties = {"myproperty = foo"})
public class TestWarSpringContext {
...
}

参见 Spring DocsJavadocs中的 @TestPropertySource

还可以使用 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
{
...
}

这样,如果应该为所有单元测试设置某个系统属性,就可以避免代码重复。

如果希望变量对所有测试都有效,可以在测试资源目录(默认情况下为 src/test/resources)中包含一个 application.properties文件,该文件如下所示:

MYPROPERTY=foo

然后,这将被加载和使用,除非您有定义通过 @TestPropertySource或类似的方法-确切的顺序,其中的属性加载可以在 Spring 文档章 24. 外部化配置中找到。

You can set the System properties as VM arguments.

如果您的项目是一个 maven 项目,那么您可以在运行测试类时执行以下命令:

mvn test -Dapp.url="https://stackoverflow.com"

测试班:

public class AppTest  {
@Test
public void testUrl() {
System.out.println(System.getProperty("app.url"));
}
}

如果您想在 eclipse 中运行单独的测试类或方法,那么:

1)转到 Run-> Run Configuration

2)在左侧选择 Junit 部分下的 Test 类。

3)采取以下措施:

enter image description here

这里的所有答案目前都只涉及系统属性,这些属性不同于更复杂的环境变量,特别是。做测试。谢天谢地,下面的类可以用来实现这一点,类文档中有很好的示例

环境变量

来自文档的一个快速示例,修改后可以使用@SpringBootTest

@SpringBootTest
public class EnvironmentVariablesTest {
@ClassRule
public final EnvironmentVariables environmentVariables = new EnvironmentVariables().set("name", "value");


@Test
public void test() {
assertEquals("value", System.getenv("name"));
}
}

对于 Unit Test,在执行“ mvn clean install”时,System 变量还没有实例化,因为没有运行应用程序的服务器。因此,为了设置 System 属性,我需要在 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>

对于 springboot,我认为这是最简单的方法,可以使用 爪哇咖啡中的 @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


}

And that's it your test should run overriding the properties with the one you have define in the annotation. 假设你有一个这样的 application.yml:

spring:
application:
name: "app"


db:
username: "user"
password: ${ENV_VARIABLE:default}

那么在测试过程中,它会是:

  • Spring 属性 spring.application.name将返回值 "example"
  • 环境变量 ENV_VARIABLE将返回 "secret",所以如果你在代码中使用值 db.password,它将返回 "secret"

如果有很多测试类(启动 tomcat/server 的 IT 测试) ,并且测试失败,则需要使用 System.setProperty("ccm.configs.dir", configPath); Since you need to make sure that is set before spring starts, you need to put it in a static context in a class. And to make sure any test that may depend on it gets this set system property, define a simple config class in your test folder setting up that variable. P.S in my case the env variable that was needed was "ccm.configs.dir" 下面是我在测试文件夹中添加的内容,

@Configuration
public class ConfigLoader {
static {
    

System.setProperty("ccm.configs.dir", "path/to/the/resource");
}


}

And all my integration test classes were able to get that variable already set by the time they are run.

@ Jimmy Praet 对 JUnit5的修改回答:

@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "classpath:whereever/context.xml")
public class TestWarSpringContext {


@BeforeAll
static void initAll() {
System.setProperty("myproperty", "foo");
}




@AfterAll
static void tearDownAll() {
System.clearProperty("myproperty");
}


...
}