2

Map を引数として取るメソッドに依存しています。

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 期待値を記述する方法はありますか?

4

2 に答える 2

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);
};

はい、これはブタ醜いです。これが私たちにできる最善のことであることをお詫び申し上げます。とはいえ、タイプをオフにする必要があることはめったにありません。ドメイン内で意味のある名前を付けることができ、ヘルパー メソッドへのチェック解除をローカライズしました。

于 2012-05-28T09:31:51.747 に答える
0

最終的に、一般的なマッチャーをより具体的なマッチャーにダウンキャストできるようにするメソッド specify() を作成しました

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")));
    }});

specify() メソッドを使用して、最も一般的なインターフェイス (Map、Collection、List、Set など) 用の特定のマッチャーを多数作成しました。

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 に追加することも提案しましたが、得られたのは沈黙だけでした。

于 2012-06-16T12:30:32.120 に答える