java代码测试环境变量_如何使用JUnit测试依赖于环境变量的代码?

如何使用JUnit测试依赖于环境变量的代码?

我有一段使用环境变量的Java代码,代码的行为取决于此变量的值。 我想用环境变量的不同值测试此代码。 我怎么能在JUnit中这样做?

我已经看到了一些在Java中设置环境变量的方法,但是我对它的单元测试方面更感兴趣,特别是考虑到测试不应该相互干扰。

11个解决方案

92 votes

库系统规则提供了用于设置环境变量的JUnit规则。

import org.junit.contrib.java.lang.system.EnvironmentVariables;

public void EnvironmentVariablesTest {

@Rule

public final EnvironmentVariables environmentVariables

= new EnvironmentVariables();

@Test

public void setEnvironmentVariable() {

environmentVariables.set("name", "value");

assertEquals("value", System.getenv("name"));

}

}

免责声明:我是系统规则的作者。

Stefan Birkner answered 2019-04-29T22:49:38Z

55 votes

通常的解决方案是创建一个管理对此环境变量的访问的类,然后可以在测试类中进行模拟。

public class Environment {

public String getVariable() {

return System.getenv(); // or whatever

}

}

public class ServiceTest {

private static class MockEnvironment {

public String getVariable() {

return "foobar";

}

}

@Test public void testService() {

service.doSomething(new MockEnvironment());

}

}

然后,受测试的类使用Environment类获取环境变量,而不是直接从System.getenv()获取。

Matthew Farwell answered 2019-04-29T22:49:09Z

9 votes

在类似的情况下,我必须编写依赖于环境变量的测试用例,我尝试了以下方法:

我按照Stefan Birkner的建议去了系统规则。 它的使用很简单。 但不久之后,我发现这种行为不稳定。 在一次运行中,它可以工作,在下一次运行中它失败了。 我调查并发现系统规则适用于JUnit 4或更高版本。 但在我的情况下,我使用的是一些依赖于JUnit 3的Jars。所以我跳过了系统规则。 更多信息,你可以在这里找到@Rule注释在JUnit中使用TestSuite时不起作用。

接下来,我尝试通过Java提供的Process Builder类创建环境变量。 通过Java Code,我们可以创建一个环境变量,但是您需要知道我没有的过程或程序名称。 它还为子进程创建环境变量,而不是为主进程创建环境变量。

我使用上述两种方法浪费了一天,但无济于事。 然后Maven来救我。 我们可以通过Maven POM文件设置环境变量或系统属性,我认为这是基于Maven的项目进行单元测试的最佳方法。 下面是我在POM文件中输入的内容。

org.apache.maven.plugins

maven-surefire-plugin

PropertyValue1

PropertyValue2

EnvironmentVariableValue1

EnvironmentVariableValue2

在此更改之后,我再次运行测试用例,突然所有工作都按预期工作。 对于读者的信息,我在Maven 3.x中探索了这种方法,所以我对Maven 2.x一无所知。

RLD answered 2019-04-29T22:50:30Z

7 votes

将Java代码与Environment变量分离,从而提供一个更抽象的变量读取器,您可以使用EnvironmentVariableReader实现您的代码来测试读取。

然后在测试中,您可以为变量阅读器提供不同的实现,以提供您的测试值。

依赖注入可以帮助解决这个问题。

Andrea Colleoni answered 2019-04-29T22:51:06Z

6 votes

这个问题的答案如何从Java设置环境变量? 提供了一种在System.getenv()中更改(不可修改的)Map的方法。 因此,虽然它并没有真正改变OS环境变量的值,但它可以用于单元测试,因为它确实改变了System.getenv将返回的内容。

sudocode answered 2019-04-29T22:51:30Z

6 votes

我不认为这已被提及,但您也可以使用Powermockito:

鉴于:

package com.foo.service.impl;

public class FooServiceImpl {

public void doSomeFooStuff() {

System.getenv("FOO_VAR_1");

System.getenv("FOO_VAR_2");

System.getenv("FOO_VAR_3");

// Do the other Foo stuff

}

}

您可以执行以下操作:

package com.foo.service.impl;

import static org.mockito.Mockito.when;

import static org.powermock.api.mockito.PowerMockito.mockStatic;

import static org.powermock.api.mockito.PowerMockito.verifyStatic;

import org.junit.Beforea;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.mockito.InjectMocks;

import org.mockito.MockitoAnnotations;

import org.powermock.core.classloader.annotations.PrepareForTest;

import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)

@PrepareForTest(FooServiceImpl.class)

public class FooServiceImpTest {

@InjectMocks

private FooServiceImpl service;

@Before

public void setUp() {

MockitoAnnotations.initMocks(this);

mockStatic(System.class); // Powermock can mock static and private methods

when(System.getenv("FOO_VAR_1")).thenReturn("test-foo-var-1");

when(System.getenv("FOO_VAR_2")).thenReturn("test-foo-var-2");

when(System.getenv("FOO_VAR_3")).thenReturn("test-foo-var-3");

}

@Test

public void testSomeFooStuff() {

// Test

service.doSomeFooStuff();

verifyStatic();

System.getenv("FOO_VAR_1");

verifyStatic();

System.getenv("FOO_VAR_2");

verifyStatic();

System.getenv("FOO_VAR_3");

}

}

Mangusta answered 2019-04-29T22:51:57Z

3 votes

我认为最干净的方法是使用Mockito.spy()。 它比创建一个单独的类来模拟和传递更轻量级。

将环境变量提取移动到另一个方法:

@VisibleForTesting

String getEnvironmentVariable(String envVar) {

return System.getenv(envVar);

}

现在在您的单元测试中执行此操作:

@Test

public void test() {

ClassToTest classToTest = new ClassToTest();

ClassToTest classToTestSpy = Mockito.spy(classToTest);

Mockito.when(classToTestSpy.getEnvironmentVariable("key")).thenReturn("value");

// Now test the method that uses getEnvironmentVariable

assertEquals("changedvalue", classToTestSpy.methodToTest());

}

pgkelley answered 2019-04-29T22:52:33Z

1 votes

希望问题得到解决。 我只是想告诉我的解决方案。

Map env = System.getenv();

new MockUp() {

@Mock

public String getenv(String name)

{

if (name.equalsIgnoreCase( "OUR_OWN_VARIABLE" )) {

return "true";

}

return env.get(name);

}

};

Muthu answered 2019-04-29T22:52:56Z

0 votes

那么你可以使用setup()方法来声明你的env的不同值。 常量中的变量。 然后在用于测试不同场景的测试方法中使用这些常量。

Cygnusx1 answered 2019-04-29T22:53:20Z

-1 votes

如果要在Java中检索有关环境变量的信息,可以调用方法:System.getenv();。作为属性,此方法返回一个Map,其中包含变量名称作为键,变量值作为映射值。 这是一个例子:

import java.util.Map;

public class EnvMap {

public static void main (String[] args) {

Map env = System.getenv();

for (String envName : env.keySet()) {

System.out.format("%s=%s%n", envName, env.get(envName));

}

}

}

方法getEnv()也可以采用参数。 例如 :

String myvalue = System.getEnv("MY_VARIABLE");

为了测试,我会做这样的事情:

public class Environment {

public static String getVariable(String variable) {

return System.getenv(variable);

}

@Test

public class EnvVariableTest {

@Test testVariable1(){

String value = Environment.getVariable("MY_VARIABLE1");

doSometest(value);

}

@Test testVariable2(){

String value2 = Environment.getVariable("MY_VARIABLE2");

doSometest(value);

}

}

Dimitri answered 2019-04-29T22:53:57Z

-1 votes

我使用System.getEnv()来获取地图,我保留为一个字段,所以我可以模拟它:

public class AAA {

Map environmentVars;

public String readEnvironmentVar(String varName) {

if (environmentVars==null) environmentVars = System.getenv();

return environmentVars.get(varName);

}

}

public class AAATest {

@Test

public void test() {

aaa.environmentVars = new HashMap();

aaa.environmentVars.put("NAME", "value");

assertEquals("value",aaa.readEnvironmentVar("NAME"));

}

}

ejaenv answered 2019-04-29T22:54:21Z


版权声明:本文为weixin_35659543原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。