2016-11-29 115 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