簡體   English   中英

在 Maven 中測試之前如何取消設置環境變量

[英]How to unset environment variable before testing in maven

我有一些依賴於環境變量的單元測試。

在使用 maven 進行測試之前,我想取消設置這些環境變量。

問題:我怎樣才能做到這一點?

不幸的是,在這種情況下,您不能使用Maven Surefire PluginenvironmentVariables選項,主要是因為它只能添加新的環境變量,而不能覆蓋(或重置,實際上等於覆蓋為空值)現有變量。

另請注意:在 Maven 中包裝並在測試之前執行的ant run也不起作用。

建議的解決方案基於 Java,尤其是基於另一篇 SO 帖子中提出的這種方法 盡管不建議用於應用程序代碼,但對於測試代碼,這種hack可能是可以接受的。

您可以將以下類添加到您的測試代碼中(在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有一定區別)中使用該類(在相關類的每個 JUnit 方法之前)
  • 在 JUnit 測試方法中使用它(自定義和縮小使用范圍)
  • 在任何執行的 JUnit 測試之前(以更全局的方式)運行它的 main 方法,如下所述(並且可能回答這個問題,即使其他場景也值得一提,恕我直言)。

讓我們來看看每個可能的解決方案。

在某個 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 測試之前運行它的 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>

請注意我們在這種情況下所做的事情:

  • 我們正在調用Exec Maven 插件java目標來實際調用我們的env hack類的mainClass
  • 我們在將classPathScope設置為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);
    }
}

這類似於上面提出的第一種和第二種方法。

請注意,要使其工作,您需要將以下依賴項添加到 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>

一般注意事項:確實不建議進行未完全隔離且取決於環境變量存在(或不存在)的測試。 您可能會遇到維護問題或遇到更棘手的故障排除,無論是為同事還是為您自己的未來。 所以,如果你真的需要它,最好正確記錄它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM