web-dev-qa-db-ja.com

mockitoで模擬リストを作成する

模擬リストを作成して、以下のコードをテストします。

 for (String history : list) {
        //code here
    }

これが私の実装です。

public static List<String> createList(List<String> mockedList) {

    List<String> list = mock(List.class);
    Iterator<String> iterHistory = mock(Iterator.class);

    OngoingStubbing<Boolean> osBoolean = when(iterHistory.hasNext());
    OngoingStubbing<String> osHistory = when(iterHistory.next());

    for (String history : mockedList) {

        osBoolean = osBoolean.thenReturn(true);
        osHistory = osHistory.thenReturn(history);
    }
    osBoolean = osBoolean.thenReturn(false);

    when(list.iterator()).thenReturn(iterHistory);

    return list;
}

しかし、テストを実行すると、次の行で例外がスローされます。

OngoingStubbing<DyActionHistory> osHistory = when(iterHistory.next());

詳細については:

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at org.powermock.api.mockito.PowerMockito.when(PowerMockito.Java:495)

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod();
Hints:
 1. missing thenReturn()
 2. you are trying to stub a final method, you naughty developer!

どうすれば修正できますか?ありがとう

25
Tien Nguyen

OK、これは悪いことです。リストをモックしないでください。代わりに、リスト内の個々のオブジェクトをモックします。 Mockito:forループでループされる配列リストのモック を参照してください。

また、なぜPowerMockを使用しているのですか? PowerMockを必要とすることは何もしていないようです。

しかし、問題の本当の原因は、スタブを完了する前に2つの異なるオブジェクトでwhenを使用していることです。 whenを呼び出して、スタブしようとしているメソッド呼び出しを提供する場合、Mockito OR PowerMockで次に行うことは、そのときに何が起こるかを指定することです。メソッドが呼び出されます-つまり、thenReturn部分を実行します。whenへの各呼び出しの後に、thenReturnへの呼び出しが1つだけ続く必要があります。 whenを呼び出すwhenを呼び出さずにthenReturnを2回呼び出した-これはエラーです。

29

リストのモックを作成し、それらを反復処理するときは、常に次のようなものを使用します。

@Spy
private List<Object> parts = new ArrayList<>();
8
lyuboe

Foreachループのリストを正しくモックできます。以下のコードスニペットと説明をご覧ください。

これは、モックリストによってテストケースを作成する実際のクラスメソッドです。 this.nameListはリストオブジェクトです。

public void setOptions(){
    // ....
    for (String str : this.nameList) {
        str = "-"+str;
    }
    // ....
}

Foreachループは内部的にイテレーターで動作するため、ここではイテレーターのモックを作成しました。 Mockitoフレームワークには、Mockito.when().thenReturn()を使用して特定のメソッド呼び出しで値のペアを返す機能があります。つまり、hasNext()で1回目のtrueと2回目の呼び出しでfalseを渡すため、ループは2回だけ継続します。 next()では、実際の戻り値を返すだけです。

@Test
public void testSetOptions(){
    // ...
    Iterator<SampleFilter> itr = Mockito.mock(Iterator.class);
    Mockito.when(itr.hasNext()).thenReturn(true, false);
    Mockito.when(itr.next()).thenReturn(Mockito.any(String.class);  

    List mockNameList = Mockito.mock(List.class);
    Mockito.when(mockNameList.iterator()).thenReturn(itr);
    // ...
}

この方法では、リストのモックを使用して、実際のリストをテストに送信することを回避できます。

4
Ashish Kirpan