如何使用 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

你在这里遇到的问题是 SpringJUnitRunnerclass 级别 是 运行 在测试 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 方法中设置。