How to Mock System.getenv (or Static Methods) In Java with Depedency Injection?


Usually, In Java, you can use @RunWith(PowerMockRunner.class) with its mockStatic method if you really want to mock the System.getenv method because it is a static. But usually this is a code smell. The usage of System.getenv e.g. if you want to read some configurations from the environment variables should be as close as to the main class/method.

Dependency Injection of the System.getenv variable

You could depdenency inject the System.getenv variable using some testing frame works, such as Google’s Guice library. With the variable injected, you then can easily mock and test it.

Testing by extracting to a private method

If somehow the dependency injection is too much a hassle to bring in, you may simply extract the variable to a method (private). For example:

1
2
3
4
5
6
7
8
9
10
11
class TestClassThatUsesSystemEnv {
    public String getOS() {
        var data = System.getenv("PATH");
        var data = getEnv("PATH");
        if (data.contains("C:\\WINDOWS")) {
            return "Windows";
        } else {
            return "Others";
        }
    }
}
class TestClassThatUsesSystemEnv {
    public String getOS() {
        var data = System.getenv("PATH");
        var data = getEnv("PATH");
        if (data.contains("C:\\WINDOWS")) {
            return "Windows";
        } else {
            return "Others";
        }
    }
}

If we want to test this method, we can extract the System.getenv into a private method and mark it @VisibleForTesting:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class TestClassThatUsesSystemEnv {
    @VisibleForTesting
    String getEnv(String key) {
        return System.getenv(key);
    }
 
    public String getOS() {
         var data = getEnv("PATH");
        if (data.contains("C:\\WINDOWS")) {
            return "Windows";
        } else {
            return "Others";
        }
    }
}
class TestClassThatUsesSystemEnv {
    @VisibleForTesting
    String getEnv(String key) {
        return System.getenv(key);
    }

    public String getOS() {
         var data = getEnv("PATH");
        if (data.contains("C:\\WINDOWS")) {
            return "Windows";
        } else {
            return "Others";
        }
    }
}

Then, we can mock it and test it with different values:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Main
{
    public static void main(String[] args) throws IOException
    {
        var test = new TestClassThatUsesSystemEnv();
        System.out.println(test.getOS());
    }
 
    private TestClassThatUsesSystemEnv instance;
    @BeforeEach
    private void setup() {
        instance = spy(TestClassThatUsesSystemEnv.class);
    }
    @Test
    public void test_OS() {
        when(instance.getEnv("PATH")).thenReturn("C:\\WINDOWS");
        assertEquals("Windows", instance.getOS());
        when(instance.getEnv("PATH")).thenReturn("/usr/bin");
        assertEquals("Others", instance.getOS());
    }
}
public class Main
{
    public static void main(String[] args) throws IOException
    {
        var test = new TestClassThatUsesSystemEnv();
        System.out.println(test.getOS());
    }

    private TestClassThatUsesSystemEnv instance;
    @BeforeEach
    private void setup() {
        instance = spy(TestClassThatUsesSystemEnv.class);
    }
    @Test
    public void test_OS() {
        when(instance.getEnv("PATH")).thenReturn("C:\\WINDOWS");
        assertEquals("Windows", instance.getOS());
        when(instance.getEnv("PATH")).thenReturn("/usr/bin");
        assertEquals("Others", instance.getOS());
    }
}

The mock instance has to be a spy, so that we can mock the method with when and call its original method getOS. It is recommended to leave out intentionally the accessor attribute such as public, private. If the test package is in the same package as the code, then it would be ok. @VisibleForTesting makes sure this helper method getEnv is only used for testing.

–EOF (The Ultimate Computing & Technology Blog) —

GD Star Rating
loading...
459 words
Last Post: Teaching Kids Programming - Longest Increasing Subsequence via Dynamic Programming Algorithm
Next Post: Teaching Kids Programming - Using a Stack to Remove All Adjacent Duplicates In String

The Permanent URL is: How to Mock System.getenv (or Static Methods) In Java with Depedency Injection?

Leave a Reply