2016-11-29 514 views
0

我想写使用Powermockito用于以下方法单元测试 -处理与泛型匿名类的Mockito

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(
    {[email protected]} 
); 

它看起来像存根不工作,我总是得到“空”这个line -

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

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

回答

3

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

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

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

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

这将对你来说特别棘手。我的正常建议是“don't mock data objects”类似于TypeReference,因为它是一个非依赖性的令牌/值/数据对象,它在反射上非常重要,但它也是它在Guice和Guava中的表兄弟的方式;你不能在你的测试中创建你自己的真实TypeReference,并将eq与你班级中的真实TypeReference进行比较。

你还是不应该嘲笑TypeReference,但你还需要调整您如何主张反对:

  • 提取匿名TypeReference子类名为等同,如果杰克逊可以让你,然后用isA来检查其类型。
  • 将TypeReference提取为一个可见的常量,并检查引用相等。
  • 使用Captor并稍后使用反射检查TypeReference的泛型类型。
  • 切换到Mockito.<TypeReference<Map<String, Object>>>any(),它在技术上Matchers类,或ArgumentMatchers更新版本的Mockito。该值不太可能发生变化,所以实际上,您的系统和测试可能会因忽视检查而变得更具可读性和可靠性,否则就不能说服PowerMock。
  • 理想情况下,尽可能使用真正的依赖关系,只需检查该功能是否有效,而不是以您的实施发生的方式与正确的协作者进行交互。一个工作职能是你无论如何,对吧?
+0

感谢您的详细解释。我切换到Mockito。>> any(),它工作。 – Saurabh