2016-08-05 11 views
1

私はListオブジェクトを受け取るメソッドを持つコールバックインターフェイスを持っています。 InOrderを使用して、コールバックメソッドが正しい順序で適切なパラメータで適切な回数呼び出されていることを確認します。InOrderを使用して、変更されたListオブジェクトでメソッド呼び出しを確認する

問題はMockitoは、私は、メソッドに同じListオブジェクトを渡すと呼び出しの間で、それを修正していますので、混乱してきているように見えるということです。 InOrder.verify()を呼び出すと、Listオブジェクトの値が、そのメソッド呼び出しが実行された時点で確認されます。

コード:

public class Test { 
    @Test 
    public void test() { 
     Callback callback = Mockito.mock(Callback.class); 
     InOrder inOrder = Mockito.inOrder(callback); 

     { 
      List<String> list = new ArrayList<String>(); //note: this List object is inaccessible from the unit test in my real use-case 
      callback.foo("name1", list); 
      list.add("value"); 
      callback.foo("name2", list); 
     } 

     inOrder.verify(callback).foo("name1", Arrays.<String> asList()); //fails here 
     inOrder.verify(callback).foo("name2", Arrays.asList("value")); 
    } 

    interface Callback { 
     void foo(String name, List<String> list); 
    } 
} 

エラーメッセージ:

Argument(s) are different! Wanted: 
callback.onFoo([]); 
Actual invocation has different arguments: 
callback.onFoo([value]); 

各コールバックメソッドの呼び出しにListオブジェクトのコピーを渡すは、テストパスを作ります。しかし、メソッドが呼び出されるたびに、新しいListを作成したくありません。

に渡すことができるMockSettingsオブジェクトを見ましたが、役立つものは何も見つかりませんでした。

This questionは鉱山に似ています。しかし、この解決策では、各メソッド呼び出しに渡されたコレクションの内容は検証されません。コレクションanyCollectionOf())が渡されたということだけを確認します。 最終結果を確認しますが、では個々の呼び出しではありません。

This answerは、潜在的な解決策を提供するように思われた。メソッドに渡されるオブジェクトを取得するのにArgumentCaptorを使用します。しかし、最初のメソッド呼び出しを検証するためにこのメソッドを使用すると、すべての変更がに行われた後にListオブジェクトが返され、テストに失敗します。 Listオブジェクトを戻す必要があります。オブジェクトの状態はListオブジェクトの状態と一致し、その正確な呼び出しはです。

ArgumentCaptor<List> argument = ArgumentCaptor.forClass(List.class); 

inOrder.verify(callback).foo(Mockito.eq("name1"), argument.capture()); 
assertEquals(Arrays.asList(), argument.getValue()); //fails: "expected: <[]> but was: <[value]> 

inOrder.verify(callback).foo(Mockito.eq("name2"), argument.capture()); 
assertEquals(Arrays.asList("value"), argument.getValue()); 

粒度を犠牲にすることなくこのテストに合格するにはどうすればよいですか?

+0

私の提案した複製で自分のanserを使用する場合は、キャプチャ機能でリストのコピーを作成します。その後、検証段階で、それらのコピーが正しいかどうかを調べることができます。 – SpaceTrucker

+0

ありがとう@SpaceTrucker。理想的ではありませんが、機能します。 – Michael

答えて

0

question that @SpaceTrucker linked toは、溶液を提供した。

基本的には、メソッドのカスタムAnswerを作成し、メソッドが呼び出されるたびにList引数のコピーを保存します。次に、すべてのコピーが期待どおりのものであることを確認します。それは理想的ではありませんが、機能します。

@Test 
public void test() { 
    Callback callback = Mockito.mock(Callback.class); 

    final List<List<String>> listParameters = new ArrayList<List<String>>(); 
    Mockito.doAnswer(new Answer<Void>() { 
     public Void answer(InvocationOnMock invocation) throws Throwable { 
      List<String> list = (List<String>) invocation.getArguments()[1]; 
      listParameters.add(new ArrayList<String>(list)); 
      return null; 
     } 
    }).when(callback).foo(Mockito.anyString(), Mockito.anyList()); 

    { 
     List<String> list = new ArrayList<String>(); //note: this List object is inaccessible from the unit test in my real use-case 
     callback.foo("name1", list); 
     list.add("value"); 
     callback.foo("name2", list); 
    } 

    InOrder inOrder = Mockito.inOrder(callback); 
    inOrder.verify(callback).foo(Mockito.eq("name1"), Mockito.anyList()); 
    inOrder.verify(callback).foo(Mockito.eq("name2"), Mockito.anyList()); 

    Assert.assertEquals(Arrays.asList(
     Arrays.asList(), 
     Arrays.asList("value") 
    ), listParameters); 
} 
+0

"それは理想的ではない"と言えば、どんなことが良いと思いますか? – SpaceTrucker

+0

@SpaceTrucker私の元のコードがうまくいけば良いでしょう。この解決法は冗長であり、よく読まない。 – Michael

関連する問題