2013-03-02 11 views
5

mam test wzdłuż tych linii:Jak zweryfikować invokations z konkretnymi dopasowujących smyczkowych w Specs2 z Mockito

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

//do my thing 

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

Działa to dobrze, ale chcę, aby upewnić się, że pierwsza rozmowa przechodzi inny organizm niż drugie połączenie. Ciało jest dość duże i nie chcę dokładnego dopasowywania na surowym przykładzie. Próbowałem to:

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

To sprawia Mockito skarżą:

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

Próbowałem również:

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

co skutkuje:

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

To wydaje mi się, że coś takiego powinno być możliwe ale nie mogę tego rozgryźć. Insights?

Odpowiedz

5

Myślę, że to jest większy problem z Mockito. Kiedy używasz Mockito z specs2 i masz wątpliwości, zawsze spaść do bezpośredniego 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") 

Możliwym rozwiązaniem jest zdefiniowanie dopasowywania że będzie sprawdzać kolejnych wartości argumentu :

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

a consecutiveValues dopasowujący jest zdefiniowany jako takie:

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

można przetestować powyższy kod. Komunikaty o błędach nie są najlepsze, ale zrób to. W tej sytuacji:

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

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

Zobaczysz:

[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

Nigdy nie było wątpliwości, że było to możliwe. Jak zwykle cieszę się, że pytam :) – iwein

+0

Nasuwa się pytanie, czy istnieje alternatywa dla Mockito dla Scali? – iwein

+0

Jest jedna alternatywa: http://scalamock.org. Ale może mógłbyś zapytać na liście mailingowej Mockito, jeśli to błąd. W takim przypadku mogą to naprawić. – Eric

Powiązane problemy