2010-04-05 28 views
12

我需要根據特定鍵值從模擬對象發送特定值。使用Mockito,我如何匹配地圖的鍵值對?

從具體類:

map.put("xpath", "PRICE"); 
search(map); 

從測試情況:

IOurXMLDocument mock = mock(IOurXMLDocument.class); 
when(mock.search(.....need help here).thenReturn("$100.00"); 

如何嘲笑這個方法調用此鍵值對?

回答

4

這不工作?

Map<String, String> map = new HashMap<String, String>(); 
map.put("xpath", "PRICE"); 
when(mock.search(map)).thenReturn("$100.00"); 

Map參數都應當遵循的其他參數相同。

+0

還有就是缺少一個右括號。 – stefanglase 2010-04-05 21:49:54

+0

IOurXMLDocument 代表我們不想爲我的單元測試調用的服務層。對於1種情況,我們用兩個不同的地圖值調用它兩次。相反,我想檢查這個值並返回一個固定的結果。因此,當應用程序代碼執行以下操作時: map.put(「xpath」,「PRODUCTNAME」); (mock.search(map))。thenReturn(「Candybar」); – Sean 2010-04-06 15:54:32

+0

不應該是mock.search(eq(map))所以它檢查實際的地圖平等? – fikovnik 2015-11-27 21:50:06

2

好像你需要的是一個Answer

IOurXMLDocument doc = mock(IOurXMLDocument.class); 
when(doc.search(Matchers.<Map<String,String>>any())).thenAnswer(new Answer<String>() { 
    @Override 
    public String answer(InvocationOnMock invocation) throws Throwable { 
     Map<String, String> map = (Map<String, String>) invocation.getArguments()[0]; 
     String value = map.get("xpath"); 
     if ("PRICE".equals(value)) { 
      return "$100.00"; 
     } else if ("PRODUCTNAME".equals(value)) { 
      return "Candybar"; 
     } else { 
      return null; 
     } 
    } 
}); 

但是,似乎是一個更好的主意是不使用原始Map作爲參數傳遞給你的搜索方法 - 你也許可以改變這個地圖與一個POJO priceproductName屬性。只是一個想法:)

15

我發現這試圖解決一個類似的問題創建一個Map參數的Mockito存根。我不想寫的地圖有問題的自定義匹配,然後我發現了一個更優雅的解決方案:使用額外的匹配在hamcrest-library用的Mockito的argThat:

when(mock.search(argThat(hasEntry("xpath", "PRICE"))).thenReturn("$100.00"); 

如果您需要檢查針對多個條目,然後您可以使用其他hamcrest超值服務:

when(mock.search(argThat(allOf(hasEntry("xpath", "PRICE"), hasEntry("otherKey", "otherValue")))).thenReturn("$100.00"); 

這將啓動與不平凡的地圖長期做下去,所以我最終提取方法收集項匹配器和我們TestUtils堅持他們:

import static org.hamcrest.Matchers.allOf; 
import static org.hamcrest.Matchers.anyOf; 
import static org.hamcrest.Matchers.hasEntry; 

import java.util.ArrayList; 
import java.util.List; 
import java.util.Map; 

import org.hamcrest.Matcher; 
--------------------------------- 
public static <K, V> Matcher<Map<K, V>> matchesEntriesIn(Map<K, V> map) { 
    return allOf(buildMatcherArray(map)); 
} 

public static <K, V> Matcher<Map<K, V>> matchesAnyEntryIn(Map<K, V> map) { 
    return anyOf(buildMatcherArray(map)); 
} 

@SuppressWarnings("unchecked") 
private static <K, V> Matcher<Map<? extends K, ? extends V>>[] buildMatcherArray(Map<K, V> map) { 
    List<Matcher<Map<? extends K, ? extends V>>> entries = new ArrayList<Matcher<Map<? extends K, ? extends V>>>(); 
    for (K key : map.keySet()) { 
     entries.add(hasEntry(key, map.get(key))); 
    } 
    return entries.toArray(new Matcher[entries.size()]); 
} 

所以我留下了:

when(mock.search(argThat(matchesEntriesIn(map))).thenReturn("$100.00"); 
when(mock.search(argThat(matchesAnyEntryIn(map))).thenReturn("$100.00"); 

有與仿製藥相關的一些醜陋,我抑制了一條警告信息,但至少它是乾燥,隱藏在TestUtil。

最後一個注意事項,請注意embedded hamcrest issues in JUnit 4.10。有了Maven,我建議首先導入Hamcrest庫,然後再導入JUnit 4.11(現在爲4。12),並排除hamcrest核心從JUnit的只是良好的措施:

<dependency> 
    <groupId>org.hamcrest</groupId> 
    <artifactId>hamcrest-library</artifactId> 
    <version>1.3</version> 
    <scope>test</scope> 
</dependency> 
<dependency> 
    <groupId>junit</groupId> 
    <artifactId>junit</artifactId> 
    <version>4.12</version> 
    <scope>test</scope> 
    <exclusions> 
     <exclusion> 
      <groupId>org.hamcrest</groupId> 
      <artifactId>hamcrest-core</artifactId> 
     </exclusion> 
    </exclusions> 
</dependency> 
<dependency> 
    <groupId>org.mockito</groupId> 
    <artifactId>mockito-all</artifactId> 
    <version>1.9.5</version> 
    <scope>test</scope> 
</dependency> 

編輯:2017年9月1日 - 每一些評論,我更新我的回答,以顯示我的Mockito依賴,我進口測試UTIL,和一個JUnit運行綠色截至今日:

import static blah.tool.testutil.TestUtil.matchesAnyEntryIn; 
import static blah.tool.testutil.TestUtil.matchesEntriesIn; 
import static org.hamcrest.MatcherAssert.assertThat; 
import static org.hamcrest.Matchers.is; 
import static org.mockito.Matchers.argThat; 
import static org.mockito.Mockito.mock; 
import static org.mockito.Mockito.when; 

import java.util.HashMap; 
import java.util.Map; 

import org.junit.Test; 

public class TestUtilTest { 

    @Test 
    public void test() { 
     Map<Integer, String> expected = new HashMap<Integer, String>(); 
     expected.put(1, "One"); 
     expected.put(3, "Three"); 

     Map<Integer, String> actual = new HashMap<Integer, String>(); 
     actual.put(1, "One"); 
     actual.put(2, "Two"); 

     assertThat(actual, matchesAnyEntryIn(expected)); 

     expected.remove(3); 
     expected.put(2, "Two"); 
     assertThat(actual, matchesEntriesIn(expected)); 
    } 

    @Test 
    public void mockitoTest() { 
     SystemUnderTest sut = mock(SystemUnderTest.class); 
     Map<Integer, String> expected = new HashMap<Integer, String>(); 
     expected.put(1, "One"); 
     expected.put(3, "Three"); 

     Map<Integer, String> actual = new HashMap<Integer, String>(); 
     actual.put(1, "One"); 

     when(sut.search(argThat(matchesAnyEntryIn(expected)))).thenReturn("Response"); 
     assertThat(sut.search(actual), is("Response")); 
    } 

    protected class SystemUnderTest { 
     // We don't really care what this does 
     public String search(Map<Integer, String> map) { 
      if (map == null) return null; 
      return map.get(0); 
     } 
    } 
} 
+2

這是一個方便的解決方案。奇怪的是,我得到了一個「錯誤的參數類型,期望Map 發現Map <?extends String,?extends String>」,java似乎無法用任何推動和導入調整來解決。我必須改變我的模擬類的方法來接受一個'Map <?擴展字符串,?擴展字符串>'讓它工作。有什麼想法嗎?我和你有junit和hamcrest相同的版本。我的Mockito是v 1.9.5。 – 2015-04-08 16:37:34

+0

@PatrickM您是否設法以更簡潔的方式解決了泛型問題?從上面我有完全相同的問題,但無法更改集合通用類型... – 2016-02-10 13:50:16

+1

@AndrewEells,不,我從來沒有找到解決方案。我從Hamcrest轉換開始使用AssertJ,因爲它的斷言似乎需要更少的類型強制。 – 2016-02-10 14:39:10

6

如果你只是想「匹配」針對特定地圖,你可以使用一些答案的上方,或自定義「匹配」擴展Map或ArgumentCaptor,如下所示:

ArgumentCaptor<Map> argumentsCaptured = ArgumentCaptor.forClass(Map.class); 
verify(mock, times(1)).method((Map<String, String>) argumentsCaptured.capture()); 
assert argumentsCaptured.getValue().containsKey("keyname"); 
// .getValue() will be the Map it called it with. 

參見更多的答案在這裏:Verify object attribute value with mockito

+1

這正是我所期待的。謝謝。 – bitoiu 2014-11-12 16:30:03

相關問題