Mock System class to get system properties
Asked Answered
E

9

18

I have a folder path set in system variable through JVM arguments in Eclipse and I am trying to access it in my class as: System.getProperty("my_files_path").

While writing junit test method for this class, I tried mocking this call as test classes do not consider JVM arguments. I have used PowerMockito to mock static System class and tried returning some path when System.getProperpty is being called.

Had @RunWith(PowerMockRunner.class) and @PrepareForTest(System.class) annotations at class level. However, System class is not getting mocked as a result I always get null result. Any help is appreciated.

Equally answered 5/12, 2013 at 15:42 Comment(0)
E
16

Thanks Satish. This works except with a small modification. I wrote PrepareForTest(PathFinder.class), preparing the class I am testing for test cases instead of System.class

Also, as mock works only once, I called my method right after mocking. My code just for reference:

@RunWith(PowerMockRunner.class)
@PrepareForTest(PathInformation.class)
public class PathInformationTest {

    private PathFinder pathFinder = new PathFinder();

@Test
    public void testValidHTMLFilePath() { 
        PowerMockito.mockStatic(System.class);
        PowerMockito.when(System.getProperty("my_files_path")).thenReturn("abc");
        assertEquals("abc",pathFinder.getHtmlFolderPath());
    }
}
Equally answered 16/12, 2013 at 21:48 Comment(0)
H
8

There are certain classes PowerMock can't mock in the usual way. See here:

This, however, may still not work. In order of "good design" preference, you can fall back to these:

  1. Refactor your code! Using a System property for passing a file path around is probably not the best way. Why not use a properties file loaded into a Properties object? Why not use getters/setters for the components that need to know this path? There are many better ways to do this.

    The only reason I could think of not to do this is you're trying to wrap a test harness around code you "can't" modify.

  2. Use @Before and @After methods to set the System property to some known value for the test(s). You could even make it part of the @Test method itself. This will be FAR easier than attempting to mock through PowerMock. Just call System.setProperty("my_files_path","fake_path");

Hornswoggle answered 5/12, 2013 at 19:0 Comment(3)
What if I need to set different values to the property in each test? In this case, @Before and @After will not work, because only static values go there.Safar
@Safar If you read the second sentence of the second list item, I mention "You could even make it part of the \@Test method itself."Hornswoggle
OK missed that. My case is a little bit different and setting the property is not working. It's an in-house annotation which read the property from the injection point. At last I wrapped getting the property into a getter and mocked that in test.Safar
K
7

System class is declared as final and cannot be mocked by libraries such as PowerMock. Several answers posted here are incorrect. If you are using Apache System Utils you can use getEnvironmentVariable method instead of calling System.getenv directly. SystemUtils can be mocked since it is not declared as final.

Kalinin answered 25/10, 2018 at 19:29 Comment(0)
N
5

Set the system property in your test and ensure that it is restored after the test by using the rule RestoreSystemProperties of the library System Rules.

public class PathInformationTest {
  private PathFinder pathFinder = new PathFinder();

  @Rule
  public TestRule restoreSystemProperties = new RestoreSystemProperties();

  @Test
  public void testValidHTMLFilePath() { 
    System.setProperty("my_files_path", "abc");
    assertEquals("abc",pathFinder.getHtmlFolderPath());
  }
}
Novice answered 4/8, 2015 at 19:59 Comment(1)
Environment Variable (retrieved with System.getenv) is not the same thing as System Property (retrieved with System.getProperty).Mythopoeia
T
2

The System.setter or getter method should be put in a user defined method and that method can be mocked to return the desired property in unit test.

public String getSysEnv(){
return System.getEnv("thisprp");
}
Tillion answered 10/8, 2020 at 17:27 Comment(1)
It doesn't even need powermock. Simple mockito can mock above call and return the desired string.Tillion
S
0

The only solution that worked for me, was wrapping getting the property into a getter method and mock the getter in test. PowerMockito and others don't work for me.

Safar answered 26/10, 2023 at 6:3 Comment(0)
E
0

In the below code, mocking behaves as expected;

@RunWith(PowerMockRunner.class)
@PrepareForTest(System.class)
public class MySuperClassTest {   
@Test
public void test(){ 
    PowerMockito.mockStatic(System.class);
    PowerMockito.when(System.getProperty("java.home")).thenReturn("abc");
    System.out.println(System.getProperty("java.home"));
}
}

But we use System.getProperty("java.home") in the real application logic not in test method. I mean not as here System.out.println(System.getProperty("java.home"))

So in the real application logic mocking didn't run well. So had to wrap System.getProperty("java.home") in a method and mock that method.

Eleventh answered 1/2, 2024 at 6:2 Comment(0)
P
-1
@RunWith(PowerMockRunner.class)
@PrepareForTest(System.class)
public class MySuperClassTest {   
@Test
public void test(){ 
    PowerMockito.mockStatic(System.class);
    PowerMockito.when(System.getProperty("java.home")).thenReturn("abc");
    System.out.println(System.getProperty("java.home"));
}
} 
Perseid answered 16/12, 2013 at 11:29 Comment(1)
Will you please share the required dependencies to this code.Astraddle
P
-1

Sailaja add System.class because as per the power mock guidelines for static,private mocking you should add the class in prepare for test.

 @PrepareForTest({PathInformation.class,System.class})

Hope this helps.let me know if it doesn't work

Perseid answered 17/12, 2013 at 4:33 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.