Reputation: 843
I am admittedly new to JMockit, but I am for some reason having trouble mocking System.getProperties(). Thanks to the help of following post:
I can successfully mock System.getProperty() using JMockit 1.12:
@Test
public void testAddSystemProperty_String() {
final String propertyName = "foo";
final String propertyValue = "bar";
new Expectations(System.class) {{
System.getProperty(propertyName);
returns(propertyValue);
}};
assertEquals(propertyValue, System.getProperty(propertyName));
}
But the eerily similar code for mocking getProperties() barfs:
@Test
public void testAddSystemProperty_String() {
final String propertyName = "foo";
final String propertyValue = "bar";
final Properties properties = new Properties();
properties.setProperty(propertyName, propertyValue);
new Expectations(System.class) {{
System.getProperties();
returns(properties);
}};
assertEquals(1, System.getProperties().size());
}
I get the following exception that points to the "returns" method:
Missing invocation to mocked type at this point;
please make sure such invocations appear only after
the declaration of a suitable mock field or parameter
Also, how do I mock both methods at the same time? If I put them in the same Expectations block (with the getProperty() first), then I do not see the exception, but System.getProperties() returns the real system properties, not the mocked ones; though getProperty(propertyName) returns the mocked value. I find that totally wonky behavior.
I see from this post that certain methods cannot be mocked, but System.getProperties() is not on that list:
JMockit NullPointerException on Exceptions block?
I am also finding that a lot of solutions on SO that worked with JMockit 2-3 years ago are totally non-compilable now, so apparently things change a lot.
Upvotes: 3
Views: 9006
Reputation: 843
Hopefully someone else finds this useful:
This can be solved with Mockito / PowerMock (1.5.3).
Note that I am testing a utility that will exhaustively try to find the property value given a list of possible sources. A source could be a system property, an environment variable, a meta-inf services file, a jndi name, a thread local, a file on disk, an ldap, basically anything that can perform a lookup.
@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassThatDirectlyCallsSystemInCaseItIsNestedLikeInMyCase.class})
public class ConfigPropertyBuilderTest {
@Test
public void testAddSystemProperty_String_using_PowerMockito() {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getProperty(propertyName)).thenReturn(propertyValue);
PowerMockito.when(System.getProperties()).thenReturn(new Properties() {{
setProperty(propertyName, propertyValue);
}});
// Here is realistic case of calling something that eventually calls System
// new configBuilder().addEnvironmentVariable(propertyName)
// .addSystemProperty(propertyName)
// .getValue();
// Here is simplified case:
assertEquals(1, System.getProperties().size());
assertEquals(propertyValue, System.getProperty(propertyName));
}
}
I could call System.setProperty(), but when you start getting into the other sources, it becomes less clear.
Note that I do not specifically care about the value returned by System.getProperty() either; I simply want to ensure that it is called if the first look up fails.
For example, in the above code snippet, the environment variable does not exist, so System.getProperty() should be called. If the environment variable existed (as it does in the next test case which is not shown), then I want to verify that System.getProperty() was not called because it should have short circuited.
Because of the difficulties in faking out the other sources using real files, real ldap, real APIs, etc, and because I want to verify certain APIs are either called or not called, and because I want to keep the tests looking consistent, I think mocking is the correct methodology (even though I may be trying to mock stuff that is not recommended in order to keep it all looking consistent). Please let me know if you think otherwise.
Also, while I do not understand the difficulties of maintaining these mocking frameworks (especially the cglib based ones), I understand the difficulties do exist and I can appreciate the sort of problems you face. My hat goes off to you all.
Upvotes: 0
Reputation: 16380
System.getProperties()
is indeed one of the methods excluded from mocking in JMockit 1.12. The exact set of such excluded methods can change in newer versions, as new problematic JRE methods are found.
There is no need to mock System.getProperty(...)
or System.getProperties()
, though. The System
class provides setProperty
and setProperties
methods which can be used instead.
Upvotes: 1