2012-05-22 52 views
2

我有一個方法,需要一個地圖作爲參數的依賴關係。JMock地圖期望

public interface Service { 
    void doSomething(Map<String, String> map); 
} 

我想寫一個斷言,這個依賴被調用與適當的地圖內容。事情是這樣的:

@RunWith(JMock.class) 
public class MainTest { 
    private Mockery context = new Mockery(); 
    private Service service = context.mock(Service.class); 
    private Main main = new Main(service); 

    @Test 
    public void test() { 
     context.checking(new Expectations(){{ 
      oneOf(service).doSomething(with(hasEntry("test", "test"))); 
     }}); 
     main.run(); 
    } 
} 

不幸的是,這不能編譯,因爲hasEntry在地圖泛型參數通配符:

public static <K, V> org.hamcrest.Matcher<java.util.Map<? extends K, ? extends V>> hasEntry(K key, V value); 

有沒有辦法寫一個JMock的expectaion在地圖內容是什麼?

回答

3

因爲我們達到了Java泛型的極限,所以沒有很好的答案。我們對jMock所需的泛型與我們需要的assertThat之間存在着一種張力()

我傾向於添加一個具有表達性名稱的助手方法來強制類型。

@Test public void test() { 
    context.checking(new Expectations(){{ 
    oneOf(service).doSomething(with(mapIncluding("test", "test"))); 
    }}); 

    main.run(); 
} 

@SuppressWarnings({"unchecked", "rawtypes"}) 
private Matcher<Map<String, String>> mapIncluding(String key, String value) { 
    return (Matcher)Matchers.hasEntry(key, value); 
}; 

是的,這是醜陋的。我只能道歉,這是我們看起來能夠做到的最好的。也就是說,我很少去關閉類型,我可以給它一個在域中有意義的名稱,並且我已經將這個取消選中的內容定位到了輔助方法。

0

我結束了創建的方法指定(),允許通用的匹配的向下轉換到更具體的人

public static <T> Matcher<T> specify(final Matcher<? super T> matcher) { 
    return new TypeSafeMatcher<T>() { 
     @Override 
     protected boolean matchesSafely(T item) { 
      return matcher.matches(item); 
     } 

     @Override 
     public void describeTo(Description description) { 
      matcher.describeTo(description); 
     } 
    }; 
} 

使用這種方法,我可以向下轉換任何現有的通用匹配,就像hasEntry()

public <K, V> Matcher<Map<? extends K, ? extends V>> hasEntry(K key, V value) 

一個更具體的一個在普通安全的方式,像這樣:

private static <K,V> Matcher<Map<K, V>> aMapHavingEntry(K key, V value) { 
    return specify(hasEntry(key, value)); 
} 

現在我可以用這個特定的匹配作爲預期參數:

context.checking(new Expectations() {{ 
     oneOf(service).doSomething(with(aMapHavingEntry("test", "test"))); 
    }}); 

使用說明()方法,我創建了最流行的接口一堆具體的匹配的:地圖,收集,列表,設置,如:

private static <K,V> Matcher<Map<K, V>> aMapHavingEntry(K key, V value) { 
    return specify(hasEntry(key, value)); 
} 

private static <K> Matcher<Collection<K>> aCollectionContainingInAnyOrder(K... items) { 
    return specify(containsInAnyOrder(items)); 
} 

我還建議在JMock中添加相同的功能,儘管我只是沉默。