在 Mockito 中使用泛型处理匿名类



>我正在尝试使用以下方法使用 Powermockito 编写单元测试 -

public String getGenerator(String json) throws IOException {
String jwt = "";
ObjectMapper mapper = new ObjectMapper();
// convert JSON string to Map
Map<String, Object> map = mapper.readValue(json, new TypeReference<Map<String, Object>>() {
}); // Here passing TypeReference annonymously
// Create a JWT
JWTGenerator generator = new JWTGenerator();
if (map != null && map.size() > 0) {
jwt = generator.createJWT(map);
}
return jwt;
}

我已将测试方法编写为-

@Test
public void testGetJWTGenerator() throws Exception {
ObjectMapper mockMapper = PowerMockito.mock(ObjectMapper.class);
PowerMockito.whenNew(ObjectMapper.class).withNoArguments().thenReturn(mockMapper);
JWTGenerator mockJWTDecoder = PowerMockito.mock(JWTGenerator.class);
PowerMockito.whenNew(JWTGenerator.class).withNoArguments().thenReturn(mockJWTDecoder);
Map<String, Object> anyMap = new HashMap<String, Object>();
anyMap.put("testStr", new Object());
TypeReference<Map<String, Object>> mockTypeReference = (TypeReference<Map<String, Object>>) PowerMockito.mock(TypeReference.class);
PowerMockito.whenNew(TypeReference.class).withNoArguments().thenReturn(mockTypeReference);
PowerMockito.when(mockMapper.readValue(Mockito.anyString(), Mockito.eq(mockTypeReference))).thenReturn(anyMap);
PowerMockito.when(mockJWTDecoder.createJWT(anyMap)).thenReturn(Mockito.anyString());
utilityController = new UtilityController();
utilityController.getJWTGenerator("{"someStr":"someStr"}");
Mockito.verify(mockJWTDecoder, Mockito.times(1)).createJWT(anyMap);
}

当我运行这个测试时,我总是失败说 -

Wanted but not invoked:
jWTGenerator.createJWT(
{testStr=java.lang.Object@24bdb479}
);

看起来存根不起作用,因为我总是为这一行得到"null" -

Map<String, Object> map = mapper.readValue(json, new TypeReference<Map<String, Object>>() {
}); // Here passing TypeReference annonymously

是因为 TypeReference 类的匿名实例化吗?

是的,这是因为匿名的内部类。 具体来说,您告诉 PowerMockito 替换对new TypeReference的调用:

PowerMockito.whenNew(TypeReference.class).withNoArguments()
.thenReturn(mockTypeReference);

但是您实际创建的是一个扩展 TypeReference 的匿名类,而不是 TypeReference 本身:

Map<String, Object> map = mapper.readValue(
json, new TypeReference<Map<String, Object>>() {});

这对你来说尤其棘手。我在这里的正常建议是"不要嘲笑数据对象",如 TypeReference,因为它是一个无依赖的令牌/值/数据对象,在反射方面大量工作,但它也不支持equalsGuice 和 Guava 中的表亲那样;与Guice和Guava不同,您不能只在测试中创建自己的真实TypeReference并与Mockito的eq匹配。

你仍然不应该嘲笑 TypeReference,但你还需要调整你对它的断言方式:

  • 如果 Jackson 允许,请将匿名 TypeReference 子类提取为命名等效项,然后使用isA检查其类型。
  • 将类型引用提取为可见常量,并检查其上的引用相等性。
  • 使用Captor并使用getType检查类型引用的泛型类型。
  • 创建一个使用getTypeArgumentMatcher实现,并将其与argThat一起使用。
  • 切换到ArgumentMatchers.any()ArgumentMatchers.<TypeReference<Map<String, Object>>>any(),以前位于MatchersMockito接口上。无论如何,该值都不太可能改变,因此,从实际意义上讲,您的系统和测试可能比通过说服 PowerMock 更具可读性和健壮性。
  • 理想情况下,尽可能使用真正的依赖项,并检查函数是否正常工作,而不是以实现的方式与正确的协作者进行交互。无论如何,工作功能都是您所追求的,对吧?

相关内容

  • 没有找到相关文章

最新更新