2017-09-01 2 views
2

私がテストしているクラスは依存関係をとり、その依存関係の関数を呼び出します。その関数は引数として複雑なオブジェクトをとり、結果を生成します。さて、私は依存関係を模擬し、渡された引数に基づいて何かを返すようにしたいと思います。単純化された作業バージョンを以下に示します。模擬クラスの引数マッチングにJava8 lambdaを使用する

whenメソッドでJava 8ラムダ式を使用してArgHasNextクラスを削除できますか?下のコメントされたコード(コンパイルされない)のようなもの。

class ArgHasNext implements ArgumentMatcher<Arg> { 
    public boolean matches(Arg arg) { 
     return arg.hasNext(); 
    } 

    @Override 
    public boolean matches(Object o) { 
     return matches((Arg)o); 
    } 
} 

@RunWith(MockitoJUnitRunner.class) 
public class ArgumentMatcherTest { 

    @Mock 
    private Dependency dep = mock(Dependency.class); 

    @Test 
    public void test() { 

     when(dep.func(argThat(new ArgHasNext()))).thenReturn(true); 
     // when(dep.func(argThat((Arg a) -> a.hasNext()))).thenReturn(true); 
     // when(dep.func(argThat((Arg a) -> !a.hasNext()))).thenReturn(false); 
     Sut sut = new Sut(dep); 
     assertEquals(sut.method(new Arg(true)), "True"); 
     assertEquals(sut.method(new Arg(false)), "False"); 
    } 
} 

class Arg { 
    private boolean hasNext; 

    public Arg(boolean hasNext) { 
     this.hasNext = hasNext; 
    } 

    public boolean hasNext() { 
     return this.hasNext; 
    } 
} 

class Sut { 
    private Dependency dep; 

    public Sut(Dependency dep) { 
     this.dep = dep; 
    } 

    public String method(Arg arg) { 

     if (dep.func(arg)) { 
      return "True"; 
     } 
     else { 
      return "False"; 
     } 
    } 

} 

class Dependency { 
    public boolean func(Arg arg) { 
     if (arg.hasNext()) { 
      return true; 
     } 
     return false; 
    } 
} 

私はMockitoコアバージョン2.0.54-βを使用しています。

EDIT わかりました。実際の場合、依存性funcメソッドは、テストされたメソッドが返される前にSUTで処理されるページングされたクエリ結果を返します。 Argに応じて、私は依存関係funcが最初に呼び出されたときにページ1の結果を返し、ページ2が2回目の結果を返すようにします。私はモックが関数呼び出しに渡された引数に基づいて異なる値を返すようにすることができます。これはMockitoのlambdasを使って可能ですか?今

+0

ちょうど不思議なことに、なぜあなたは何歳の2.0ベータ版を使用していますか?そしておそらく、ここでラムダを使ってどのように想像しているのか、例を挙げられますか? – GhostCat

+0

@GhostCatテストメソッドの2つのコメント行を見てください。私はそれらの2つの行がはるかに表現力があると思う(彼らが働くならば)。 ArgumentMatcher派生クラスは機能しますが、明白ではありません。 – MvdD

+0

多分私は何かを逃していますが、間違った場所にあなたの時間を投資していると思います。私の答えを見てください。 – GhostCat

答えて

3

、私は依存関係を模擬し、それが渡された引数に基づいて何かを返すようにしたいと思います。

あなたが最初の場所でそれを行うべきではありません。 万一、あなたのモックがよく定義された定数値を返すようにしてください。

なぜなら、テストコードが間違っているためにテストが失敗するリスクを減らすために、テストコードをできるだけシンプルに保つ必要があるからです。

doAnswer(new Answer<YourReturnType>(){ 
    public YourReturnType answer(InvocationOnMock invocation) { 
     YourParameterType parameter = (YourParameterType)invocation.getArguments()[0]; 
     // calculate your return value 
     return yourCalculatedReturnValue; 
    } 
}).when(yourMock).theMethod(any(YourParameterType.class)); 

は明確にするために、私のモックが一定値を返している:


あなたの問題を解決するには、mockitos Answerインタフェースであるかもしれません。モックは複数回呼び出され、2回目に別の値を返すようにします。 - MvdD

これはあなたの質問に書かれているはずです。解決策は、それが聞こえるように簡単です:

doReturn(VALUE_FOR_FIRST_CALL). 
    thenReturn(VALUE_FOR_SECOND_CALL). 
    thenReturn(VALUE_FOR_ANY_FURTHER_CALL). 
    when(mock).theMethod(); 

それとも、あまりおしゃべりであることを好む場合:

doReturn(VALUE_FOR_FIRST_CALL, VALUE_FOR_SECOND_CALL, VALUE_FOR_ANY_FURTHER_CALL). 
    when(mock).theMethod(); 
+0

''新しい回答 'の代わりに、ラムダがもっと簡潔になります。 –

+0

@ A.H。私はラムダも書いていますが、*匿名のクラス*フォームはnewbeeの方が説明力があります。 –

+0

明確にするために、私のモックは一定の値を返しています。モックは複数回呼び出され、2回目に別の値を返すようにします。 – MvdD

2

私はあなたが間違ったウサギの穴を下っていると思います。意味:模擬仕様は模擬仕様です。それらは何か他ならないはずです。

私は何を意味することは次のとおりです。

@Test 
public void testForTrue() { 
    when(dep.func(any()).thenReturn(true); 
    Sut sut = new Sut(dep); 
    assertEquals(sut.method(new Arg(true)), "True"); 
} 

@Test 
public void testForFalse() { 
    when(dep.func(any()).thenReturn(false); 
    Sut sut = new Sut(dep); 
    assertEquals(sut.method(new Arg(false)), "False"); 
} 

全く場合は、私は、その後にリファクタリングになります:

private void testFor(boolean depReturnValue, expectedResult) { 
    when(dep.func(any()).thenReturn(depReturnValue); 
    Sut sut = new Sut(dep); 
    assertEquals(sut.method(new Arg(depReturnValue)), expectedResult); 
} 

と@Testメソッドからそのメソッドを呼び出して、私はあなたのようなテストを書くことを示唆しています上で概説したように。

他の言い方をすれば、「インテリジェントな」モック仕様を得るのに多くの時間とエネルギーを費やす必要はありません。むしろ、簡単なストレートフォワードテストの作成に焦点を当てています。

として書くと、虚偽の呼び出しに渡された引数について複雑な分析が行われます。

+0

私の例では完全にクリアされていないかもしれません。要点は、依存関係が複数回呼び出され、毎回異なる値を返すようにすることです。私は明確にするために質問を編集しました。 – MvdD

+0

しかし、まだ少なくともあなたの** assertに*同じ*引数を使用している 'sut.method()'の**使用法**によると、ですから、dep.func()は同じオブジェクトで呼び出され、常に同じ値を返しますか? – GhostCat

+0

もう一度簡単な例があります。実際には、次の依存関係呼び出しの引数は 'sut.method()'の内部で生成され、最初の呼び出しの戻り値に依存します。 – MvdD

2

私自身の質問に答える。モックメソッドが別の複雑な引数オブジェクトで複数回呼び出されたため、渡された引数に応じてモックを何か別のものに戻すようにすることにも焦点を合わせました。

解決策は、Mockitoを使用して簡単な次の呼び出しで異なる結果を返すことでした。

@RunWith(MockitoJUnitRunner.class) 
public class ArgumentMatcherTest { 

    @Mock 
    private Dependency dep = mock(Dependency.class); 

    @Test 
    public void test() { 

     // return true on first invocation, false on second. 
     when(dep.func(anyObject())).thenReturn(true).thenReturn(false); 

     Sut sut = new Sut(dep); 
     assertEquals(sut.method(new Arg(true)), "True"); 
     assertEquals(sut.method(new Arg(false)), "False"); 
    } 
} 
関連する問題