2013-03-02 7 views
5

でSpecs2内の特定の文字列マッチャとinvokationsを確認するにはどうすればよい私はこれらの線に沿ってテストを持っている:私はMockito

httpClient.post(anyString, anyString) returns (first, second) 

//do my thing 

there were two(httpClient).post(anyString, anyString) 

これは正常に動作しますが、私は最初の呼び出しがとは異なる体を渡すことを確認したいです2番目の呼び出し。ボディはかなり大きく、私は厳密な例で正確なマッチングをしたくありません。 Mockitoを作る

there was one(httpClientMock).postMessage(anyString, argThat(contain("FOO")) 
there was one(httpClientMock).postMessage(anyString, argThat(contain("FOO")) 

が文句を言う:

InvalidUseOfMatchersException: 
[error] Invalid use of argument matchers! 
[error] 2 matchers expected, 3 recorded: 

私も試してみた:私はこれを試してみたその結果

there was one(httpClientMock).postMessage(argThat(contain("foo")), argThat(contain("FOO"))) 
    there was one(httpClientMock).postMessage(argThat(contain("foo")), argThat(contain("FOO"))) 

Wanted 1 time: 
[error] -> ... 
[error] But was 2 times. Undesired invocation: ... 

それこのような何かが可能でなければならないと私に思われるしかし、私はそれを把握していないようです。洞察?

答えて

5

これはMockitoの問題点です。あなたはspecs2とMockitoを使用していて、疑問にいるときは、必ず直接Mockito APIにドロップダウン:この周り

// simplified httpClient with only one parameter 
val httpClient = mock[HttpClient] 
httpClient.post(anyString) returns "" 

httpClient.post("s1") 
httpClient.post("s2") 

// forget specs2 
// there was two(httpClient).post(anyString) 

org.mockito.Mockito.verify(httpClient, org.mockito.Mockito.times(1)).post("s1") 

// I guess that you don't want this to pass but it does 
org.mockito.Mockito.verify(httpClient, org.mockito.Mockito.times(1)).post("s1") 

1つの可能な方法は、引数の連続値をチェックしますマッチャーを定義することです:

there was two(httpClient).post(consecutiveValues(===("s1"), ===("s2"))) 

そしてconsecutiveValuesマッチャーは、次のように定義されます

import matcher._ 
import MatcherImplicits._ 

// return a matcher that will check a value against a different 
// `expected` matcher each time it is invoked 
def consecutiveValues[T](expected: Matcher[T]*): Matcher[T] = { 
    // count the number of tested values 
    var i = -1 

    // store the results 
    var results: Seq[(Int, MatchResult[T])] = Seq() 

    def result(t: T) = { 
    i += 1 
    // with Mockito values are tested twice 
    // the first time we return the result (but also store it) 
    // the second time we return the computed result 
    if (i < expected.size) { 
     val mr = expected(i).apply(Expectable(t)) 
     results = results :+ (i, mr) 
     mr 
    } else results(i - expected.size)._2 
    } 

    // return a function that is translated to a specs2 matcher 
    // thanks to implicits 
    // display the failing messages if there are any 
    (t: T) => (result(t).isSuccess, 
      results.filterNot(_._2.isSuccess).map { case (n, mr) => 
       s"value $n is incorrect: ${mr.message}" }.mkString(", ")) 
} 

あなたは上記のコードをテストすることができます。失敗メッセージは最高ではありませんが、トリックを行います。このような状況で:

httpClient.post("s1") 
httpClient.post("s2") 

there was two(httpClient).post(consecutiveValues(===("s1"), ===("s3"))) 

あなたが表示されます。

[error] x test 
[error] The mock was not called as expected: 
[error] httpClient.post(
[error]  value 1 is incorrect: 's2' is not equal to 's3' 
[error] ); 
[error] Wanted 2 times: 
[error] -> at ... 
[error] But was 1 time: 
[error] -> at ... 
+0

私はそれが可能だったことは間違いではなかったです。いつものように、私は喜んで私は尋ねた:) – iwein

+0

ScalaのためのMockitoに代わるものがなければならないのですか? – iwein

+0

1つの選択肢があります:http://scalamock.org。しかし、もしこれがバグであればMockitoのメーリングリストで尋ねることができます。その場合、彼らはそれを修正するかもしれません。 – Eric