zjf*_*fdu 5 java testing unit-testing maven
我有一些依赖于环境变量的单元测试。
我想在使用 Maven 测试之前取消设置这些环境变量。
问题:我怎样才能实现这一目标?
不幸的是,在这种情况下,您无法使用Maven Surefire PluginenvironmentVariables的选项,主要是因为它只能添加新的环境变量,而不能覆盖(或重置,实际上等于覆盖为空值)现有变量。
另请注意:在 Maven 中包装并在测试之前执行的ant 运行也不起作用。
所提出的解决方案基于 Java,特别是基于另一篇 SO 帖子中提出的这种方法。虽然对于应用程序代码来说是不可取的,但是对于测试代码来说这种技巧可能是可以接受的。
您可以将以下类添加到您的测试代码中(在 下src/test/java):
package com.sample;
import java.lang.reflect.Field;
import java.util.Map;
public class EnvHack {
@SuppressWarnings("unchecked")
public static void resetEnvironmentVariable(String name, String value) throws Exception {
Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
theEnvironmentField.setAccessible(true);
Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
env.put(name, value);
Field theCaseInsensitiveEnvironmentField = processEnvironmentClass
.getDeclaredField("theCaseInsensitiveEnvironment");
theCaseInsensitiveEnvironmentField.setAccessible(true);
Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
cienv.put(name, value);
}
public static void main(String[] args) throws Exception {
resetEnvironmentVariable("test_prop", "test_value");
}
}
Run Code Online (Sandbox Code Playgroud)
上面的类基本上是破解 Java API 以更改内存中环境变量的值。因此,它们可以设置为不同的值、重置,甚至实际上取消设置(将其从地图中删除)。
由于该类现在是测试代码的一部分,因此您有多种选择:
@Before方法(或者@BeforeClass,有一定区别)中使用该类(在相关类的每个 JUnit 方法之前)让我们看一下每种可能的解决方案。
@Before在某个 JUnit 测试用例的方法中使用该类
package com.sample;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class MainTest {
@Before
public void init() throws Exception {
EnvHack.resetEnvironmentVariable("test_prop", "test_value");
}
@Test
public void testEnvProperty() throws Exception {
String s = System.getenv("test_prop");
Assert.assertEquals(s, "test_value");
}
}
Run Code Online (Sandbox Code Playgroud)
这个解决方案可以在每个测试类中使用,并且当一组测试(方法)共享相同的需求时(建议:如果它们不这样做,这可能是一个提示,可能应该移出某些方法)。
在 JUnit 测试方法中使用它
package com.sample;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class MainTest {
@Before
public void init() throws Exception {
EnvHack.resetEnvironmentVariable("test_prop", "test_value");
}
@Test
public void testEnvProperty() throws Exception {
EnvHack.resetEnvironmentVariable("test_prop", "test_value2");
String s = System.getenv("test_prop");
Assert.assertEquals(s, "test_value2");
}
}
Run Code Online (Sandbox Code Playgroud)
该解决方案提供了最高的自由度:您可以在需要时准确地使用相关变量,尽管可能会出现代码重复,但它也可以强制测试隔离。
在执行任何 JUnit 测试之前运行其 main 方法
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.4.0</version>
<executions>
<execution>
<phase>process-test-classes</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>com.sample.EnvHack</mainClass>
<classpathScope>test</classpathScope>
</configuration>
</execution>
</executions>
</plugin>
Run Code Online (Sandbox Code Playgroud)
请注意我们在这种情况下所做的事情:
java的目标来实际调用我们的env hack类。mainClassclassPathScopeset to调用它test,以便使其对 Enforcer 插件可见process-test-classes,只是为了确保它在test阶段之前执行,因此在任何测试之前执行。该解决方案集中了整个准备环境过程,一次即可完成所有测试。
另一方面,您也可以考虑在测试中使用模拟。这不是一个集中选项(除非您对其进行编码),但可以提供进一步的提示,因此值得一提。这是通过 PowerMock 重置环境变量的示例代码
package com.sample;
import org.junit.*;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest(System.class)
public class EnvTest {
@Before
public void init() {
PowerMockito.mockStatic(System.class);
Mockito.when(System.getenv("TEST_PROP")).thenReturn("TEST_VALUE");
}
@Test
public void test() {
String var = System.getenv("TEST_PROP");
Assert.assertEquals("TEST_VALUE", var);
}
}
Run Code Online (Sandbox Code Playgroud)
这与上面提出的第一种和第二种方法类似。
请注意,要使其正常工作,您需要将以下依赖项添加到 POM 中:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>1.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.5</version>
<scope>test</scope>
</dependency>
</dependencies>
Run Code Online (Sandbox Code Playgroud)
一般注意事项:实际上,不建议进行未完全隔离且依赖于环境变量是否存在(或不存在)的测试。为了同事或你自己的未来,你可能会遇到维护问题或遇到更棘手的故障排除。因此,如果您确实需要它,最好正确记录它。
| 归档时间: |
|
| 查看次数: |
6032 次 |
| 最近记录: |