With the following test I have an invalid stub setup. The mock requestBuilder
is stubbed with the param "INCORRECT"
, whereas the class under test invokes it with "/socket"
.
My experience with Mockito in JUnit tells me that the invocation at runtime will result in null
. However, I'm seeing a false positive. The test passes & the requestBuilder
is returning the mock request
, even though it is invoked with "/socket"
.
Why is this? Has it something to do with having more than one expectation? If so, the final expectation is the one that counts and it should fail.
class ChannelSpec extends Specification with Mockito with ScalaCheck with ArbitraryValues { def is = s2"""
A Channel must
send an open request to /socket with provided channel name on instantiation $sendToSocket
"""
def sendToSocket = prop{(name: String, key: Key, secret: Secret) =>
val requestBuilder = mock[(String, Seq[Map[String, String]]) => Req]
val request = mock[Req]
val httpRequestor = mock[(Req) => Future[String]]
val result = mock[Future[String]]
val params = Seq(Map("key" -> key.value, "timestamp" -> anyString, "token" -> anyString), Map("channel" -> name))
requestBuilder("INCORRECT", params) returns request
httpRequestor(request) returns result
new Channel(name, key, secret, requestBuilder = requestBuilder, httpRequestor = httpRequestor)
there was one(requestBuilder).apply("INCORRECT", params)
println("expecting " + request)
there was one(httpRequestor).apply(request)
}
While I don't know Scala, I do know that anyString
doesn't do what you think it does. Specifically, all Mockito matchers work through side effects, adding the related String objects to ArgumentMatcherStorage
as I described toward the end of this SO answer.
Consequently, you can't really extract matchers into variables:
// This is fine, because the parameters are evaluated in order.
takesTwoParameters(eq("A"), eq("B")) returns bar
// Now let's change it a little bit.
val secondParam = eq("SECOND")
val firstParam = eq("FIRST")
// At this point, firstParam == secondParam == null, and the hidden argument
// matcher stack looks like [eq("SECOND"), eq("FIRST")]. That means that your
// stubbing will apply to takesTwoParameters("SECOND", "FIRST"), not
// takesTwoParameters("FIRST", "SECOND")!
takesTwoParameters(firstParam, secondParam)) returns bar
Furthermore, you can't nest anyString
into arbitrary types like Seq or Map; Mockito's argument matchers are designed to match entire arguments.
Your best bet is to use argThat
for your params, and create a small Hamcrest matcher that checks that the argument you're checking is properly formed. That will give you the flexibility of checking that your params are roughly what you expect, while ignoring the values you don't care about.