首页 > 解决方案 > 使用 powerMockito 的 JUnit 测试提供了 NPE

问题描述

我有一个班级,我想为其编写一个 Junit 单元测试用例。

public class ComparatorUtil {

    public static Map<String, ValueDifference<Object>> compareJsonObject(Object srcObject, Object targetObject)
                throws JsonGenerationException, JsonMappingException, IOException {
        String initialJson = ConverterUtil.convertObjectToJson(srcObject);
        String updatedJson = ConverterUtil.convertObjectToJson(targetObject);
        Gson g = new Gson();
        Type mapType = new TypeToken<Map<String, Object>>(){}.getType();
        Map<String, Object> firstMap = g.fromJson(initialJson, mapType);
        Map<String, Object> secondMap = g.fromJson(updatedJson, mapType);
        Map<String, MapDifference.ValueDifference<Object>> diffMap = Maps.difference(firstMap, secondMap).entriesDiffering();
        return diffMap;
    }
}


public class ConverterUtil {

    public static String convertObjectToJson(Object o)
            throws JsonGenerationException, JsonMappingException, IOException {
        ObjectMapper mapperObj = new ObjectMapper();
        return mapperObj.writeValueAsString(o);
    }
}

我写的Junit测试用例:-

@RunWith(PowerMockRunner.class)
@PrepareForTest(ConverterUtil.class)
public class ComparatorUtilTest {

    @Before
    public void setUp() {
        PowerMockito.mockStatic(ConverterUtil.class);
    }

    @Test
    public void testValueDiff() throws JsonGenerationException, JsonMappingException, IOException {
        TestObject srcObject = new TestObject();
        srcObject.setColor("white");
        srcObject.setId(1);
        TestObject targetObj = new TestObject();
        targetObj.setColor("white");
        targetObj.setId(1);
        targetObj.setSuffix("AA");
        ComparatorUtil.compareJsonObject(srcObject, targetObj);
        PowerMockito.verifyStatic(VerificationModeFactory.times(2));
        ConverterUtil.convertObjectToJson(srcObject);
        ConverterUtil.convertObjectToJson(targetObj);
    }
}

当我运行测试类时,我得到了一个Null Pointer ExceptioninitialJson并且updatedJson将变为空。谁能告诉我我在哪里做错了?

标签: junitmockitopowermockito

解决方案


这里有很多事情错了。

  • 您似乎假设如何使用 PowerMock。但是你放在一起的东西根本没有意义!例如,您需要使用“when().thenReturn()”创建一个模拟规范。
  • 含义:仅指示 PowerMock 将模拟某个类是不够的。当调用这些静态方法时,您必须告诉 PowerMock 要返回的实际值。
  • 因此,首先要从头到尾阅读一个好的教程。不要将 PowerMock 用于您自己的代码,而是看看教程如何解决一个简单的问题。

那么:PowerMock 需要付出一定的代价。所以你避免使用它。您宁愿退后一步,重新审视您的代码,以便可以在不需要模拟静态方法的情况下对其进行测试。你看,我们正在谈论将一些输入转换为一些输出的代码。对于这种情况,您应该能够编写完全不需要模拟的生产和测试代码。如果有的话,您应该使用诸如 Mockito 之类的框架——好的生产代码可以在没有 PowerMock 的情况下进行测试。

更具体地说:为什么需要模拟静态方法?这似乎表明您的 ObjectMapper 在您的单元测试设置中不起作用。它从那里开始!

你看,你的转换方法的一个好的单元测试应该看起来像:

assertThat(someConverterUnderTest.convert(fineTunedInput), is(expectedOutput));

而已!您应该设计您的转换器以完全在您的单元测试环境中工作。然后所有对模拟的需求都消失了。换句话说:您当前正在测试实现细节。相反,您应该始终尝试测试您的方法的公共合约。测试实现细节有时是不可避免的,但如前所述:您在此处显示的代码真的应该在没有模拟的情况下进行测试。

然后:即使您需要模拟:静态方法也会妨碍您。这是一个明确的信号,您不应该在这里使用静态!相反,您将那些可能需要模拟的元素转换为参数或被测类的字段。因为那样你就可以简单地注入模拟对象。这意味着您不再需要 PowerMock(ito) 工具。


推荐阅读