Reputation: 261
I'm able to mock the System.getenv value from Junit but when I execute the test case - in my service class System.getevn value coming as null. Not sure what I'm doing wrong here. Please find my test service class and junit class.
Can some please help me to fix this issue - why the value is not setting in my actual service class?
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() {
}
}
Upvotes: 4
Views: 1490
Reputation: 247153
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.
Upvotes: 2