3

Map<String,Widget>プロパティを含む単純なPOJOがあります。

private Map<String, Widget> widgetCache = new HashMap<String, Widget>();

@Override
public Logger newWidget(String name, Widget widget) {
    // First, print the contents of widgetCache in pretty print format.
    Map<String, Widget> map = widgetCache;
    List<String> keys = new ArrayList<String>(map.keySet());
    System.out.println("Printing..." + keys.size());
    for (String key: keys)
        System.out.println(key + ": " + map.get(key).getName());

    if(!widgetCache.containsKey(name)) {
        System.err.println("I don't contain " + name);
        widgetCache.put(name, widget);
    }

    return widgetCache.get(name);
}

Widget非常に単純です。重複したをマップに挿入することはできません。Mockito(1.9.5)を使用してJUnitテストメソッドでこれをテストする場合:

CachingWidgetFactory fixture = new CachingWidgetFactory();

// By the way, I get errors if I try to make this next line:
//        HashMap<String,Widget> mockMap = Mockito.mock(HashMap<String,Widget>.class);
// How do I enforce generics here when defining a mock?
HashMap mockMap = Mockito.mock(HashMap.class);

fixture.setLoggerCache(mockMap);

fixture.newWidget("Widget-A", new Widget("Widget-A"));
fixture.newWidget("Widget-A", new Widget("Widget-A"));

Mockito.verify(mockMap, Mockito.times(1))
        .put(Mockito.anyString(), Mockito.<Logger>any());

次のJUnit出力でテストが失敗します。

org.mockito.exceptions.verification.TooManyActualInvocations: 
hashMap.put(<any>, <any>);
Wanted 1 time:

そして、(STDOUT)コンソール出力には、次のように表示されます。

Printing...0
I don't contain Widget-A
Printing...0
I don't contain Widget-A

したがって、Mockitoが返しているモックは、2番目の(重複した)挿入を許可しているように見えます。ただし、MockitoをmockMap完全に削除して、テストメソッドを次のようにすると、次のようになります。

CachingWidgetFactory fixture = new CachingWidgetFactory();

fixture.newWidget("Widget-A", new Widget("Widget-A"));
fixture.newWidget("Widget-A", new Widget("Widget-A"));

次に、コンソール出力で、次のようになります。

Printing...0
I don't contain Widget-A
Printing...1

これで、(モックされていない)コードが重複挿入を正しく防止しています。つまり、Mockitoが呼び出されるHashMapたびに新しいものを返してnewWidgetいるようです。ここで何が起こっているのか、そしてその理由は?(そして、上記の一般的な問題について私を助けることができればボーナスポイント。)よろしくお願いします。

4

2 に答える 2

2

それはよくある間違いです。あなたはあなたが嘲笑したことを覚えておく必要がありますHashMap。したがって、mockitoは毎回新しいマップを提供するわけではなく、HashMapをモックしたため、動作方法がわからないだけです。

それを与えると、あなたがそれを振る舞うように言うようにそれは振る舞います。何も言っていない場合は、メソッドを呼び出すときにデフォルト値を返すか、何もしません。だから、ラインで

 if (!widgetCache.containsKey(name))

動作方法を指定しなかったため、デフォルト値の。が返されますfalse。Mockitoを次のように使用して、2回目の呼び出しでマップをモックしてfalseを返すことができます。

 given(hashMap.containsKey(name)).willReturn(false, true);

containsKeyこれにより、HashMapは、指定された名前のの2回目の呼び出しでキーを「含む」ものを返します。ここでそのドキュメントを読むことができます

あなたができるもう一つのことはそれにHashMapの実際の実装を与えることです、しかし私は「モック」の方法を好みます:)

編集

BDDMockitoへのリンクを指定しましたが、when->でも同じように機能しthenReturnます。単なるシンタックスシュガーです:)読みやすいと思います。

于 2013-02-04T19:45:22.027 に答える
0
// How do I enforce generics here when defining a mock?
HashMap mockMap = Mockito.mock(HashMap.class);

mockitoアノテーションを使用すると、ジェネリックスの処理がはるかに簡単になります。

@Mock
HashMap<String, Widget> mockMap;

次に、セットアップ方法で:

MockitoAnnotations.init(this);

しかし、あなたの問題には、

HashMap<String, Widget> map=new HashMap<String, Widget>();

テストでは、1つのように動作する実際のHashMapを使用します。これは、テストしたいものだからです。すべてのHashMap操作を自分でモックする場合は、何らかの間違いを犯している可能性があります(メソッドのモックを忘れるなど)。

于 2013-02-04T20:11:09.993 に答える