java如何在maven中测试之前取消设置环境变量 7 月 Questions & Answers 4055 我有一些依赖于环境变量的单元测试 我想在使用maven进行测试之前取消设置这些环境变量 问题:我如何才能做到这一点
# 1 楼答案 不幸的是,在这种情况下,您不能使用Maven Surefire Plugin的^{}选项,主要是因为它只能添加新的环境变量,而不能覆盖(或重置,实际上等于覆盖为空值)现有变量 还要注意:用Maven包装并在测试之前执行的ant run也不起作用 提出的解决方案基于Java,尤其是另一篇SO帖子中提出的this approach。虽然对于应用程序代码来说不可取,但对于测试代码来说,这种攻击可能是可以接受的 您可以将以下类添加到测试代码中(在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"); } } 上面的类基本上是对Java API进行黑客攻击,以更改内存中环境变量的值。因此,它们可以设置为不同的值,重置,甚至取消设置(从映射中删除) 由于该类现在是测试代码的一部分,您有几个选项: 在某个JUnit测试用例的@Before方法(或@BeforeClass,with a certain difference)中使用该类(在相关类的每个JUnit方法之前) 在JUnit测试方法中使用它(自定义和缩小使用范围) 在执行任何JUnit测试之前运行它的主方法(以更全局的方式),如下所述(可能会回答这个问题,尽管其他场景也值得一提,imho)李> 让我们看看每个可能的解决方案 在某个JUnit测试用例的@Before方法中使用该类 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"); } } 当一组测试(方法)共享相同的需求时(建议:如果它们不共享,这可能是一个提示,可能应该删除某些方法),每个测试类都可以使用此解决方案 在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"); } } 这个解决方案提供了最高的自由度:您可以在需要的地方精确地使用相关变量,尽管可能会出现代码重复,但它也可以强制执行测试隔离 在执行任何JUnit测试之前运行其主方法 <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> 注意我们在这种情况下所做的: 我们正在调用Exec Maven Plugin的^{}目标来实际调用我们的环境黑客类的mainClass李> 我们调用它时classPathScope设置为test,以使它对Enforcer插件可见 我们将它作为^{}阶段的一部分运行,只是为了确保它在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); } } 这与上文提出的第一种和第二种方法类似 请注意,要使其正常工作,您需要将以下依赖项添加到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> 一般注意事项:确实,不建议进行未完全隔离的测试,并取决于环境变量的存在(或不存在)。您可能会遇到维护问题,或者遇到更棘手的故障排除,无论是对同事还是对您的未来都是如此。所以,如果你真的需要它,最好把它记录下来
# 1 楼答案
不幸的是,在这种情况下,您不能使用Maven Surefire Plugin的^{} 选项,主要是因为它只能添加新的环境变量,而不能覆盖(或重置,实际上等于覆盖为空值)现有变量
还要注意:用Maven包装并在测试之前执行的ant run也不起作用
提出的解决方案基于Java,尤其是另一篇SO帖子中提出的this approach。虽然对于应用程序代码来说不可取,但对于测试代码来说,这种攻击可能是可以接受的
您可以将以下类添加到测试代码中(在
src/test/java
下):上面的类基本上是对Java API进行黑客攻击,以更改内存中环境变量的值。因此,它们可以设置为不同的值,重置,甚至取消设置(从映射中删除)
由于该类现在是测试代码的一部分,您有几个选项:
@Before
方法(或@BeforeClass
,with a certain difference)中使用该类(在相关类的每个JUnit方法之前)让我们看看每个可能的解决方案
在某个JUnit测试用例的
@Before
方法中使用该类当一组测试(方法)共享相同的需求时(建议:如果它们不共享,这可能是一个提示,可能应该删除某些方法),每个测试类都可以使用此解决方案
在JUnit测试方法中使用它
这个解决方案提供了最高的自由度:您可以在需要的地方精确地使用相关变量,尽管可能会出现代码重复,但它也可以强制执行测试隔离
在执行任何JUnit测试之前运行其主方法
注意我们在这种情况下所做的:
mainClass
李>classPathScope
设置为test
,以使它对Enforcer插件可见test
阶段之前执行,因此在任何测试之前执行李>该解决方案集中了整个准备环境过程,一次用于所有测试
另一方面,你也可以考虑在测试中使用嘲讽。这不是一个集中的选项(除非您编写代码),但可能会给出进一步的提示,因此值得一提。下面是通过PowerMock重置环境变量的示例代码
这与上文提出的第一种和第二种方法类似
请注意,要使其正常工作,您需要将以下依赖项添加到POM中:
一般注意事项:确实,不建议进行未完全隔离的测试,并取决于环境变量的存在(或不存在)。您可能会遇到维护问题,或者遇到更棘手的故障排除,无论是对同事还是对您的未来都是如此。所以,如果你真的需要它,最好把它记录下来