2013-03-02 50 views
5

我沿着这些线路测试:如何验证与Specs2特定字符串的匹配invokations用的Mockito

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

//do my thing 

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

这工作得很好,但我想验证第一个呼叫通过不同的身体比第二个电话。身体比较大,我不想在一个严格的例子上做精确的匹配。我已经试过这样:

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

这使得抱怨的Mockito:

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: ... 

它在我看来,像这样的东西应该是possi可是,我似乎无法弄清楚。见解?

回答

5

我认为这是Mockito首先遇到的问题。当你使用带的Mockito和specs2你有疑问的时候,总是下降到直接API的Mockito:

// 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") 

解决此问题的可能的方法是定义一个匹配,将检查参数的连续值:

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 2013-03-02 19:40:06

+0

它引发了一个问题,应该有一个替代Mockito for Scala? – iwein 2013-03-02 19:41:25

+0

还有一个选择:http://scalamock.org。但是也许你可以在Mockito邮件列表上询问这是否是一个错误。在这种情况下,他们可能会修复它。 – Eric 2013-03-02 23:08:35

相关问题