如何在JUnit 5的测试用例中设置环境变量?

26
我正在使用JUnit 5进行工作。我的Java代码使用System.getenv("demoVar")来访问环境变量。
在JUnit 5测试类中,我如何设置这个环境变量,以便在测试期间我的代码可以访问它的值?

3
为什么这被标记为重复?重复的问题中的答案是关于Java系统属性的。而这个问题是关于环境变量的。System.getenv与System.getProperty是完全不同的。尝试使用System.setEnv("", "")!!:)因此,那个回答对于这个问题是无效的。正确的回答应该是JUnit5中system-rules的替代方案。 - angelcervera
这显然不是@angelcervera所提到的重复。 - andgalf
3
在Java 8中,您可以更改调用System.getenv()方法的方式,以便使用Function<String, String>。在您的生产代码中,您将使用System::getenv,在您的测试代码中,您可以在填充了测试值的内部Map上使用Map::get。 - Matthias Bohlen
6个回答

16

从另一个Stack Overflow答案https://dev59.com/yVYN5IYBdhLWcg3w07Bx#59635733中得知:

有一个“JUnit 5扩展包”——JUnit Pioneer。

jUnit Pioneer提供了一个注释,用于为测试设置环境变量。例如:

@Test
@SetEnvironmentVariable(key = "PATH", value = "")
void testPath_isEmpty() {
    assertThat(System.getenv("PATH")).isEmpty();
}

6
这会在 JDK9-16 中发出警告,并在 JDK17 中抛出 InaccessibleObjectException 异常。 - Bala
5
这个库的存储库中存在一个问题,讨论了在使用该注释时出现的警告和错误,并提供了解决方法。 https://github.com/junit-pioneer/junit-pioneer/issues/509 - Miguel Ferreira
感谢@Miguel Ferreira提供的信息。(虽然还有一些解决方法,但我们计划移除环境变量依赖,而不是使用这些解决方法)。再次感谢您的时间。 - Bala
@Bala Pioneer专门为这个“问题”开设了一个完整的章节:https://junit-pioneer.org/docs/environment-variables/#warnings-for-reflective-access - beatngu13

8

您无法通过使用getenv来更改这些环境值,因为它们是不可变的。一种方法是启动另一个虚拟机或另一个进程,在其中可以引入新的环境值。

另一种方法是切换到System.getProperty,但务必了解其差异。

https://www.baeldung.com/java-system-get-property-vs-system-getenv

这里是一个小测试代码:

public class EnvironmentVarsTest {
    private static int counter = 0;

    @BeforeEach
    public void setUp() {
        counter = counter + 1;
        System.setProperty("simple_test_env_property", String.valueOf(counter));
    }

    @Test
    public void testFirst() {
        printOutValues();
    }

    @Test
    public void testSecond() {
        printOutValues();
    }

    private void printOutValues() {
        System.out.println("--------------------");
        System.out.println("val=" + counter);
        System.out.println("envval=" + System.getProperty("simple_test_env_property"));
    }

}

1
有一个黑科技可以让你从Java代码中为当前进程设置环境变量。这并不美观,除非你真的需要它,否则不应该使用它。另一方面,Java应该真正拥有一种适当的方法来完成这个任务,而不是诉诸于黑科技。 - sigint
注意:有一些库可以让你轻松地完成这个任务。然而,从Java 16开始,反射技巧不再起作用。https://github.com/webcompere/system-stubs提供了一个基于Mockito的解决方案,可以解决这个问题。 - Ashley Frieze

3
这可以通过 https://github.com/webcompere/system-stubs/tree/master/system-stubs-jupiter 实现。

@ExtendWith(SystemStubsExtension.class)
class TestClass {

    @SystemStub
    private EnvironmentVariables environmentVariables =
        new EnvironmentVariables("demoVar", "val");

    @Test
    void test() {
        // can use the environment
        assertThat(System.getenv("demoVar")).isEqualTo("val");

        // can also change the environment
        environmentVariables.set("foo", "bar");

        // environment variables restored to previous state when
        // test ends
    }
}

不支持 Kotlin v1.9 和 Java 17。 - Phil
请在 GitHub 项目上提出一个问题。它肯定可以与 Java 17 配合使用,尽管不能在多线程代码中生存。 - Ashley Frieze

2

0
这里有一个使用 Kotlin DSL(build.gradle.kts)的解决方案:
tasks.withType<Test> {
    environment["myFirst"] = "bunny"
    // OR
    environment(
        "mySecond" to "7249",
        "myThird" to "curtain"
    )
}

环境变量将在测试和主要代码中都可用:
val name = System.getenv().get("myFirst")

附注:您还可以根据环境变量禁用/启用您的测试:

@Test
@EnabledIfEnvironmentVariable(named = "myFirst", matches = "bunny", disabledReason = "Oh no")
public void myTest() {
    // ...
}

0
通常的做法是使用系统属性而不是环境变量。 在这种情况下,您将使用选项 -D demoVar =“{your_value}”运行您的java / maven / gradle命令或任何您用于运行测试的命令。 对于maven目标:
 maven clean install -DdemoVar="test"

适用于Java Jar:

 java -jar xxx.jar -DdemoVar="test"

您可以通过代码获取它,使用 System.getProperty("demoVar")

如果您确实需要使用环境变量,请使用操作系统功能。对于Linux:

demoVar="test" mvn clean install

对于 Windows PowerShell:

$env:demoVar = 'test'; mvn clean install

1
谢谢!$env:demoVar = 'test'; mvn clean install - 快速简单且有效。 - MeIr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接