2013-03-02 26 views
5

ile Specs2 belirli dize matchers ile invokations nasıl doğrularım ben bu satırlar boyunca bir test var:Ben Mockito

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

//do my thing 

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

Bu iyi çalışır, ancak ilk çağrı farklı bir vücuda geçer doğrulamak istiyorum ikinci arama. Vücut oldukça büyük ve sıkı bir örnek üzerinde kesin eşleme yapmak istemiyorum. Mockito yapar

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

şikayet:

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

Ben de denedim: Bu denedim sonuçlanır

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

O Bana böyle bir şey possi olmalı Biraz ama bunu anlayamıyorum. Insights?

cevap

5

Bunun, Mockito ile başlaması için bir problem olduğunu düşünüyorum. Eğer specs2 ile Mockito kullanıyor ve şüpheye olduğunuzda, her zaman doğrudan mockito API açılır:

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

bu çevrede olası bir yolu bir argüman ardışık değerleri kontrol edecek bir eşleyici tanımlamaktır :

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

Ve consecutiveValues eşleştirici gibi tanımlanır:

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(", ")) 
} 

yukarıdaki kodu test edebilirsiniz. Hata mesajları en iyisi değil, hile yapar. Bu durumda:

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

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

göreceksiniz:

[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

Bunun mümkün olduğunu şüphe yoktu. Her zamanki gibi, sorduğuma sevindim :) – iwein

+0

Scala için Mockito'nun alternatifi olmalı mı sorusunu soruyor? – iwein

+0

Bir alternatif var: http://scalamock.org. Ama bu bir hata ise Mockito posta listesine sorabilirsiniz. Bu durumda onu düzeltebilirler. – Eric