junit - 使用 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 Exception
,initialJson
并且updatedJson
将变为空。谁能告诉我我在哪里做错了?
解决方案
这里有很多事情错了。
- 您似乎假设如何使用 PowerMock。但是你放在一起的东西根本没有意义!例如,您需要使用“when().thenReturn()”创建一个模拟规范。
- 含义:仅指示 PowerMock 将模拟某个类是不够的。当调用这些静态方法时,您必须告诉 PowerMock 要返回的实际值。
- 因此,首先要从头到尾阅读一个好的教程。不要将 PowerMock 用于您自己的代码,而是看看教程如何解决一个简单的问题。
那么:PowerMock 需要付出一定的代价。所以你避免使用它。您宁愿退后一步,重新审视您的代码,以便可以在不需要模拟静态方法的情况下对其进行测试。你看,我们正在谈论将一些输入转换为一些输出的代码。对于这种情况,您应该能够编写完全不需要模拟的生产和测试代码。如果有的话,您应该使用诸如 Mockito 之类的框架——好的生产代码可以在没有 PowerMock 的情况下进行测试。
更具体地说:为什么需要模拟静态方法?这似乎表明您的 ObjectMapper 在您的单元测试设置中不起作用。它从那里开始!
你看,你的转换方法的一个好的单元测试应该看起来像:
assertThat(someConverterUnderTest.convert(fineTunedInput), is(expectedOutput));
而已!您应该设计您的转换器以完全在您的单元测试环境中工作。然后所有对模拟的需求都消失了。换句话说:您当前正在测试实现细节。相反,您应该始终尝试测试您的方法的公共合约。测试实现细节有时是不可避免的,但如前所述:您在此处显示的代码真的应该在没有模拟的情况下进行测试。
然后:即使您需要模拟:静态方法也会妨碍您。这是一个明确的信号,您不应该在这里使用静态!相反,您将那些可能需要模拟的元素转换为参数或被测类的字段。因为那样你就可以简单地注入模拟对象。这意味着您不再需要 PowerMock(ito) 工具。
推荐阅读
- perl - 从字符串中减去一行中的多个大写字母
- cqengine - CQEngine 查询开销/预编译参数化查询
- gnuplot - 在 GNUPLOT 中用日期/时间 x 轴标记点
- c++ - 如何读取以方括号开头的Json字符串?
- html - 使用 CSS 更改链接元素中的文本
- sql - 使用 Oracle SQL,如何在不使用 PIVOT、LISTAGG 或自定义构建函数的情况下将多行数据连接到一行?
- anylogic - 单个路径代理的统计信息
- php - 登录重定向后 symfony 3.4 失去会话
- php - array_multisort 对多字节和上升
- c# - 用于复杂查询的 MongoDB C# 数组过滤器