vit*_*aut 113 java testing junit unit-testing environment-variables
我有一段使用环境变量的Java代码,代码的行为取决于此变量的值.我想用环境变量的不同值测试此代码.我怎么能在JUnit中这样做?
Ste*_*ner 164
库系统规则提供了用于设置环境变量的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"));
}
}
Run Code Online (Sandbox Code Playgroud)
免责声明:我是系统规则的作者.
Mat*_*ell 64
通常的解决方案是创建一个管理对此环境变量的访问的类,然后可以在测试类中进行模拟.
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());
}
}
Run Code Online (Sandbox Code Playgroud)
然后,受测试的类使用Environment类获取环境变量,而不是直接从System.getenv()获取.
RLD*_*RLD 18
在类似的情况下,我必须编写依赖于环境变量的测试用例,我尝试了以下方法:
我使用上述两种方法浪费了一天,但无济于事.然后Maven来救我.我们可以通过Maven POM文件设置环境变量或系统属性,我认为这是基于Maven项目进行单元测试的最佳方法.下面是我在POM文件中输入的内容.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<PropertyName1>PropertyValue1</PropertyName1>
<PropertyName2>PropertyValue2</PropertyName2>
</systemPropertyVariables>
<environmentVariables>
<EnvironmentVariable1>EnvironmentVariableValue1</EnvironmentVariable1>
<EnvironmentVariable2>EnvironmentVariableValue2</EnvironmentVariable2>
</environmentVariables>
</configuration>
</plugin>
</plugins>
</build>
Run Code Online (Sandbox Code Playgroud)
在此更改之后,我再次运行测试用例,突然所有工作都按预期工作.对于读者的信息,我在Maven 3.x中探索了这种方法,所以我对Maven 2.x一无所知.
小智 12
我不认为这已被提及,但您也可以使用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
}
}
Run Code Online (Sandbox Code Playgroud)
您可以执行以下操作:
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");
}
}
Run Code Online (Sandbox Code Playgroud)
将Java代码与Environment变量分离,从而提供一个更抽象的变量读取器,您可以使用EnvironmentVariableReader实现您的代码来测试读取.
然后在测试中,您可以为变量阅读器提供不同的实现,以提供您的测试值.
依赖注入可以帮助解决这个问题.
对于 JUnit 4 用户,Stefan Birkner建议的System Lambda非常适合。
如果您使用的是 JUnit 5,则有JUnit Pioneer扩展包。它带有@ClearEnvironmentVariable和@SetEnvironmentVariable。从文档:
的
@ClearEnvironmentVariable和@SetEnvironmentVariable注释可用于清除,分别设置环境变量的值对于一个测试执行。这两个注释都适用于测试方法和类级别,既可重复又可组合。被注解的方法被执行后,注解中提到的变量将恢复到它们的原始值,或者如果它们之前没有的话将被清除。测试期间更改的其他环境变量不会恢复。
例子:
@Test
@ClearEnvironmentVariable(key = "SOME_VARIABLE")
@SetEnvironmentVariable(key = "ANOTHER_VARIABLE", value = "new value")
void test() {
assertNull(System.getenv("SOME_VARIABLE"));
assertEquals("new value", System.getenv("ANOTHER_VARIABLE"));
}
Run Code Online (Sandbox Code Playgroud)
这个答案的问题如何设置环境变量从Java?提供了一种在System.getenv()中更改(不可修改的)Map的方法.因此,虽然它并没有真正改变OS环境变量的值,但它可以用于单元测试,因为它确实改变了System.getenv将返回的内容.
我认为最简单的方法是使用Mockito.spy()。它比创建单独的类进行模拟和传递要轻巧一些。
将获取环境变量移至另一种方法:
@VisibleForTesting
String getEnvironmentVariable(String envVar) {
return System.getenv(envVar);
}
Run Code Online (Sandbox Code Playgroud)
现在在您的单元测试中执行以下操作:
@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());
}
Run Code Online (Sandbox Code Playgroud)
小智 5
希望问题得到解决。我只是想告诉我的解决方案。
Map<String, String> env = System.getenv();
new MockUp<System>() {
@Mock
public String getenv(String name)
{
if (name.equalsIgnoreCase( "OUR_OWN_VARIABLE" )) {
return "true";
}
return env.get(name);
}
};
Run Code Online (Sandbox Code Playgroud)
尽管我认为这个答案最适合 Maven 项目,它也可以通过反射实现(在Java 8 中测试):
public class TestClass {
private static final Map<String, String> DEFAULTS = new HashMap<>(System.getenv());
private static Map<String, String> envMap;
@Test
public void aTest() {
assertEquals("6", System.getenv("NUMBER_OF_PROCESSORS"));
System.getenv().put("NUMBER_OF_PROCESSORS", "155");
assertEquals("155", System.getenv("NUMBER_OF_PROCESSORS"));
}
@Test
public void anotherTest() {
assertEquals("6", System.getenv("NUMBER_OF_PROCESSORS"));
System.getenv().put("NUMBER_OF_PROCESSORS", "77");
assertEquals("77", System.getenv("NUMBER_OF_PROCESSORS"));
}
/*
* Restore default variables for each test
*/
@BeforeEach
public void initEnvMap() {
envMap.clear();
envMap.putAll(DEFAULTS);
}
@BeforeAll
public static void accessFields() throws Exception {
envMap = new HashMap<>();
Class<?> clazz = Class.forName("java.lang.ProcessEnvironment");
Field theCaseInsensitiveEnvironmentField = clazz.getDeclaredField("theCaseInsensitiveEnvironment");
Field theUnmodifiableEnvironmentField = clazz.getDeclaredField("theUnmodifiableEnvironment");
removeStaticFinalAndSetValue(theCaseInsensitiveEnvironmentField, envMap);
removeStaticFinalAndSetValue(theUnmodifiableEnvironmentField, envMap);
}
private static void removeStaticFinalAndSetValue(Field field, Object value) throws Exception {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, value);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
100238 次 |
| 最近记录: |