如何使用 Spring 框架为 Junit 测试设置环境变量
How to Set Environment Varibles for Junit Tests with Spring Framework
我有一个 class,它只是 returns 带有 System.getEnv
的环境变量,我正在尝试为它编写一个 JUnit 测试,但我总是得到 null。
我正在尝试将 application-test.yml
与所有变量集一起使用,并尝试了许多注释,例如
@RunWith(SpringJUnit4ClassRunner.class)
@TestPropertySource(locations="classpath:/application-test.yml")
还有很多其他的,但仍然没有成功。有谁知道如何简单地做到这一点?
Spring与环境变量无关。它可以读取它们,但据我所知不会说任何内容,这与系统属性不同。
环境变量是存在于环境中的。
所以你有以下选择:
选项 1
使用允许模拟静态方法调用的 Power Mock。这个库不是 spring 的一部分,所以你可以只在测试范围内使用它,这样它就不会影响生产(powermock jar 不会在生产依赖列表中)
选项 2
用一些外部 class 包装静态调用,然后用常规模拟框架模拟它/或加载同一接口的不同 bean,因为您正在使用 Spring 测试。代码看起来像这样:
interface EnvAccessor {
String getValue(String envVarName);
}
public class MyEnvAccessor {
String getValue(String envVarName) {
return System.getenv(envVarName);
}
}
选项 3
除了在 JUnit 测试开始之前以编程方式设置 env 变量外,在生产代码中什么也不做:
public class SampleTest {
@BeforeClass
public static void setupEnvironment() {
// set the environment here
}
}
现在,特别是从测试和 java 代码设置环境是非常棘手的,因为环境变量不应该以编程方式更改。
您可以阅读 Here 了解可能的解决方法并在您的程序中对其进行评估。
有多种方法。
选项 1
如果您在 IDE(eclipse 或 IntelliJ IDEA)中进行 运行 测试,则可以在 IDE 中为测试设置变量。如果您使用的是 Maven,则可以通过 Surefire 插件设置系统属性 - https://maven.apache.org/surefire/maven-surefire-plugin/examples/system-properties.html
<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<systemProperties>
<property>
<name>buildDir</name>
<value>${project.build.outputDirectory}</value>
</property>
</systemProperties>
</configuration>
</plugin>
</plugins>
</build>
[...]
</project>
选项 2
使用 Spring EL
"classpath:config_#{systemProperties['env']}/db.properties"
可以在此处找到更多详细信息 - how to read System environment variable in Spring applicationContext
你在这里遇到的问题是 SpringJUnitRunner
在 class 级别 是 运行 在测试 class。一种解决方案是将 spring 测试包装在父 class 中,并在其中设置环境变量 class.
这在 JUnit 5 中使用系统存根更容易实现 - https://github.com/webcompere/system-stubs
这是来自那里的 spring 示例 (https://github.com/webcompere/system-stubs/blob/master/system-stubs-jupiter/src/test/java/uk/org/webcompere/systemstubs/jupiter/examples/SpringAppWithDynamicPropertiesTest.java):
@ExtendWith(SystemStubsExtension.class)
public class SpringAppWithDynamicPropertiesTest {
private static WireMockServer wireMock = new WireMockServer(Options.DYNAMIC_PORT);
// sets the environment before Spring even starts
@SystemStub
private static EnvironmentVariables environmentVariables;
@BeforeAll
static void beforeAll() {
// we can manipulate the env vars here
environmentVariables.set("SERVER_URL", "something");
}
@Nested
@SpringBootTest(classes = {RestApi.class, App.class},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class InnerSpringTest {
@LocalServerPort
private int serverPort;
@Test
void someTest() {
// the spring app is testable with the given env
}
}
}
我认为在 JUnit 4 中也可以实现同样的效果,使用 Enclosed
runner 作为外部 class,并使用 EnvironmentVariablesRule
作为静态成员,使用环境变量在外部 class 的 @BeforeClass
方法中设置。
我有一个 class,它只是 returns 带有 System.getEnv
的环境变量,我正在尝试为它编写一个 JUnit 测试,但我总是得到 null。
我正在尝试将 application-test.yml
与所有变量集一起使用,并尝试了许多注释,例如
@RunWith(SpringJUnit4ClassRunner.class)
@TestPropertySource(locations="classpath:/application-test.yml")
还有很多其他的,但仍然没有成功。有谁知道如何简单地做到这一点?
Spring与环境变量无关。它可以读取它们,但据我所知不会说任何内容,这与系统属性不同。
环境变量是存在于环境中的。
所以你有以下选择:
选项 1
使用允许模拟静态方法调用的 Power Mock。这个库不是 spring 的一部分,所以你可以只在测试范围内使用它,这样它就不会影响生产(powermock jar 不会在生产依赖列表中)
选项 2
用一些外部 class 包装静态调用,然后用常规模拟框架模拟它/或加载同一接口的不同 bean,因为您正在使用 Spring 测试。代码看起来像这样:
interface EnvAccessor {
String getValue(String envVarName);
}
public class MyEnvAccessor {
String getValue(String envVarName) {
return System.getenv(envVarName);
}
}
选项 3
除了在 JUnit 测试开始之前以编程方式设置 env 变量外,在生产代码中什么也不做:
public class SampleTest {
@BeforeClass
public static void setupEnvironment() {
// set the environment here
}
}
现在,特别是从测试和 java 代码设置环境是非常棘手的,因为环境变量不应该以编程方式更改。
您可以阅读 Here 了解可能的解决方法并在您的程序中对其进行评估。
有多种方法。
选项 1
如果您在 IDE(eclipse 或 IntelliJ IDEA)中进行 运行 测试,则可以在 IDE 中为测试设置变量。如果您使用的是 Maven,则可以通过 Surefire 插件设置系统属性 - https://maven.apache.org/surefire/maven-surefire-plugin/examples/system-properties.html
<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<systemProperties>
<property>
<name>buildDir</name>
<value>${project.build.outputDirectory}</value>
</property>
</systemProperties>
</configuration>
</plugin>
</plugins>
</build>
[...]
</project>
选项 2
使用 Spring EL
"classpath:config_#{systemProperties['env']}/db.properties"
可以在此处找到更多详细信息 - how to read System environment variable in Spring applicationContext
你在这里遇到的问题是 SpringJUnitRunner
在 class 级别 是 运行 在测试 class。一种解决方案是将 spring 测试包装在父 class 中,并在其中设置环境变量 class.
这在 JUnit 5 中使用系统存根更容易实现 - https://github.com/webcompere/system-stubs
这是来自那里的 spring 示例 (https://github.com/webcompere/system-stubs/blob/master/system-stubs-jupiter/src/test/java/uk/org/webcompere/systemstubs/jupiter/examples/SpringAppWithDynamicPropertiesTest.java):
@ExtendWith(SystemStubsExtension.class)
public class SpringAppWithDynamicPropertiesTest {
private static WireMockServer wireMock = new WireMockServer(Options.DYNAMIC_PORT);
// sets the environment before Spring even starts
@SystemStub
private static EnvironmentVariables environmentVariables;
@BeforeAll
static void beforeAll() {
// we can manipulate the env vars here
environmentVariables.set("SERVER_URL", "something");
}
@Nested
@SpringBootTest(classes = {RestApi.class, App.class},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class InnerSpringTest {
@LocalServerPort
private int serverPort;
@Test
void someTest() {
// the spring app is testable with the given env
}
}
}
我认为在 JUnit 4 中也可以实现同样的效果,使用 Enclosed
runner 作为外部 class,并使用 EnvironmentVariablesRule
作为静态成员,使用环境变量在外部 class 的 @BeforeClass
方法中设置。