【问题标题】:JMockit - "Missing invocation to mocked type" when mocking System.getProperties()JMockit - 模拟 System.getProperties() 时“缺少对模拟类型的调用”
【发布时间】:2014-11-04 17:25:27
【问题描述】:

诚然,我是 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());
}

我得到以下指向“returns”方法的异常:

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

另外,我如何同时模拟这两种方法?如果我将它们放在同一个 Expectations 块中(首先使用 getProperty() ),那么我看不到异常,但 System.getProperties() 返回真实的系统属性,而不是模拟的;虽然 getProperty(propertyName) 返回模拟值。我发现这种行为完全不可靠。

我从这篇文章中看到某些方法不能被模拟,但 System.getProperties() 不在该列表中:

JMockit NullPointerException on Exceptions block?

我还发现,2-3 年前与 JMockit 一起使用的许多 SO 解决方案现在完全不可编译,因此显然情况发生了很大变化。

【问题讨论】:

    标签: java unit-testing jmockit


    【解决方案1】:

    System.getProperties() 确实是 JMockit 1.12 中排除的模拟方法之一。随着新的有问题的 JRE 方法被发现,这些排除方法的确切集合可能会在较新的版本中发生变化。

    不过,没有必要模拟 System.getProperty(...)System.getProperties()System 类提供了setPropertysetProperties 方法,可以替代使用。

    【讨论】:

    • 明白。我在哪里可以找到这份清单?最终目标是模拟 System.getenv() ,您不能简单地为其设置属性而没有一些讨厌的反射。至于使用 System.setProperty(),我可以回答“为什么不使用 Mockito/PowerMock”。有时替代方案是不够的。
    • 另外,如果可能的话,如果这种情况下的异常更清楚地表明 API 不可模拟,那就太好了。
    • 没有这样的列表,因为1)它不稳定,因为它总是可以在下一个版本中改变; 2)它实际上包含了来自 JRE 类的极少数方法/构造函数,而且几乎可以肯定,用户一开始就不应该嘲笑它们(除非通过实际示例测试证明)。至于使异常更清楚,我将尝试检测从期望块内部对不可模拟方法的调用,以便可以抛出特定异常(对于 JMockit 1.14)。
    【解决方案2】:

    希望其他人觉得这很有用:

    这可以通过 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() 返回的值;我只是想确保在第一次查找失败时调用它。

    比如上面代码sn-p中,环境变量不存在,所以应该调用System.getProperty()。如果环境变量存在(正如在下一个未显示的测试用例中所做的那样),那么我想验证 System.getProperty() 是否没有被调用,因为它应该短路了。 p>

    因为使用真实文件、真实 ldap、真实 API 等伪造其他来源的困难,并且因为我想验证某些 API 是否被调用,并且因为我想保持测试看起来一致,我认为模拟是正确的方法(即使我可能试图模拟不推荐的东西以保持一切看起来一致)。如果您有其他想法,请告诉我。

    另外,虽然我不理解维护这些模拟框架(尤其是基于 cglib 的框架)的困难,但我理解这些困难确实存在,并且我能理解您所面临的问题。我向你们所有人致敬。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多