如何使用Spring框架为Junit测试设置环境变量

时间:2018-10-06 11:32:57

标签: spring-boot junit4

我有一个仅使用System.getEnv返回环境变量的类,并且我正在尝试为此编写JUnit测试,但是我总是得到null。 我正在尝试将application-test.yml与所有变量一起使用,并尝试了许多注释,例如

@RunWith(SpringJUnit4ClassRunner.class)
@TestPropertySource(locations="classpath:/application-test.yml")

和许多其他方法,但仍然没有成功。有谁知道如何简单地做到这一点?

3 个答案:

答案 0 :(得分:1)

有多种方法。

选项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

答案 1 :(得分:0)

Spring与环境变量无关。它可以读取它们,但据我所知,它不会说任何东西,与系统属性不同。

环境变量本应存在于环境中。

因此,您有以下选择:

选项1

使用Power Mock,它可以模拟出静态方法调用。该库不是spring的一部分,因此您可以在测试范围内使用它,以免对生产产生影响(powermock jar将不在生产依赖项列表中)

选项2

用一些外部类包装静态调用,然后使用常规的模拟框架对其进行模拟/或加载相同接口的不同bean,因为无论如何您都在使用Spring Test。该代码将如下所示:

  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有关可能的解决方法的信息,并在程序中对其进行评估。

答案 2 :(得分:0)

您在这里遇到的问题是 SpringJUnitRunner 在测试类中的任何方法之前在类级别运行。一种解决方案是将 spring 测试包装在一个父类中,并在该类中设置环境变量。

使用系统存根在 JUnit 5 中更容易实现 - https://github.com/webcompere/system-stubs

这是一个弹簧示例 (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 运行器作为外部类并使用 EnvironmentVariablesRule 作为静态成员,并在外部类的 { 中设置环境变量{1}} 方法。