如何在Junit PowerMockito中使用System.getenv

时间:2018-03-25 15:31:17

标签: java junit mockito powermockito

我能够从Junit模拟System.getenv值,但是当我执行测试用例时 - 在我的服务类System.getevn中,值为null。不知道我在这里做错了什么。请找我的测试服务类和junit类。

有些人可以帮我修复这个问题 - 为什么价值没有在我的实际服务类中设置?

TestService.java

public class TestService {

    public TestService() throws Exception {

        loadTestMethod();

    }

    private void loadTestMethod() {

        System.out.println("Environment vairlable : " + System.getenv("my_key_name"));
        System.setProperty("app.key", System.getenv("my_key_name"));

    }

}

TestServiceTest.java

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(value = { System.class })
@PowerMockIgnore("javax.management.*")

public class TestServiceTest {

    @Mock
    TestService testService;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);

        PowerMockito.mockStatic(System.class);
        PowerMockito.when(System.getenv("my_key_name")).thenReturn("Testing");
        System.out.println("Junit Environment vairlable : " + System.getenv("my_key_name"));
        testService = new TestService();

    }

    @Test
    public void myServiceTest() {

    }
}

1 个答案:

答案 0 :(得分:1)

Just because PowerMockito allows us to mock static does not mean that we should.

Your classes are dependent on static implementation concerns that make unit testing in isolation, in most cases, difficult.

Consider following the Explicit Dependency Principle

Methods and classes should explicitly require (typically through method parameters or constructor parameters) any collaborating objects they need in order to function correctly.

Create an abstraction of the desired functionality

public interface SystemWrapper {
    //The "standard" output stream
    PrintStream out;
    //Gets the value of the specified environment variable
    string getenv(string name);
    //Sets the system property indicated by the specified key.
    string setProperty(String key, String value);
}

The implementation will encapsulate the actual calls to the static system class

public class SystemWrapperImplementation implements SystemWrapper {
    //The "standard" output stream
    public final PrintStream out = System.out;

    //Gets the value of the specified environment variable
    public string getenv(string name) {
        return System.getenv(name);
    }

    //Sets the system property indicated by the specified key.
    public string setProperty(String key, String value) {
        return System.setProperty(key, value);
    }
}

Your dependent class will then need to be refactored to include the abstraction

public class TestService {
    private SystemWrapper system;

    public TestService(SystemWrapper system) throws Exception {
        this.system = system;
        string key = "app.key";
        string name = "my_key_name";
        loadTestMethod(key, name);
    }

    private void loadTestMethod(string key, string name) {
        string environmentVariable = system.getenv(name);
        system.out.println("Environment variable : " + environmentVariable);
        system.setProperty(key, environmentVariable);
    }
}

Now for testing you can mock the necessary dependencies as needed without any adverse effects. The implementation will then be used in production when invoking actual code.

Finally I would suggest not having your constructors throwing exceptions. Constructors should mainly be used for assignments of variables.