诚然,我是JMockit的新手,但由于某种原因,我在模仿System.getProperties()时遇到了困难。感谢以下帖子的帮助:
https://stackoverflow.com/questions/25664270/how-can-i-partially-mock-the-system-class-with-jmockit-1-8?lq=1
我可以使用JMockit 1.12:成功模拟System.getProperty()
@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));
}
但是用于嘲笑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());
}
我得到了以下指向"return"方法的异常:
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
此外,我如何同时模拟这两种方法?如果我把它们放在同一个Experts块中(首先使用getProperty()),那么我看不到异常,但System.getProperties()返回真实的系统属性,而不是模拟的属性;尽管getProperty(propertyName)返回模拟值。我觉得这种行为完全不稳定。
我从这篇文章中看到,某些方法不能被嘲笑,但System.getProperties()不在这个列表中:
异常块上的JMockit NullPointerException?
我还发现,2-3年前与JMockit合作的许多SO解决方案现在完全不可编译,所以显然情况发生了很大变化。
System.getProperties()
确实是JMockit 1.12中排除在mocking之外的方法之一。当发现新的有问题的JRE方法时,这类排除方法的确切集合在较新版本中可能会发生变化。
不过,没有必要模拟System.getProperty(...)
或System.getProperties()
。System
类提供了可以替代使用的setProperty
和setProperties
方法。
希望其他人能发现这一点:
这可以通过Mockito/PowerMock(1.5.3)解决
请注意,我正在测试一个实用程序,该实用程序将在给定一系列可能的源的情况下,竭尽全力查找属性值。源可以是系统属性、环境变量、meta-inf服务文件、jndi名称、本地线程、磁盘上的文件、ldap,基本上是任何可以执行查找的东西。
@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));
}
}
我可以调用System.setProperty(),但当您开始进入其他源时,它就不那么清楚了。
请注意,我也不特别关心System.getProperty()返回的值;我只是想确保在第一次查找失败时调用它。
例如,在上面的代码片段中,环境变量不存在,因此应该调用System.getProperty()。如果环境变量存在(就像在下一个未显示的测试用例中一样),那么我想验证System.getProperty()是否被调用而不是,因为它应该短路了。
由于使用真实文件、真实ldap、真实API等伪造其他来源的困难,并且因为我想验证某些API是否被调用,也因为我想保持测试的一致性,我认为模拟是正确的方法(尽管我可能试图模拟不推荐的东西,以保持所有东西的一致性)。如果你不这么认为,请告诉我。
此外,虽然我不理解维护这些嘲讽框架(尤其是基于cglib的框架)的困难,但我理解这些困难确实存在,我可以理解你面临的那种问题。我向你们致敬。