Mockito: 0 matchers expected, 1 recorded - scala

I have the folliwng PlaySpec:
"Service A" must {
"do the following" in {
val mockServiceA = mock[ServiceA]
val mockServiceB = mock[ServiceB]
when(mockServiceA.applyRewrite(any[ClassA])).thenReturn(resultA) // case A
when(mockServiceB.execute(any[ClassA])).thenReturn(Future{resultB})
// test code continuation
}
}
The definition of ServiveA and ServiceB are
class ServiceA {
def applyRewrite(instance: ClassA):ClassA = ???
}
class ServiceB {
def execute(instance: ClassA, limit: Option[Int] = Some(3)) = ???
}
Mocking ServiceA#applyRewrite works perfectly.
Mocking ServiceB#execute fails with the following exception:
Invalid use of argument matchers!
0 matchers expected, 1 recorded:
-> at RandomServiceSpec.$anonfun$new$12(RandomServiceSpec.scala:146)
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
Although the instructions included in the exception seem a bit counterintuitive to me I have tried the following:
when(mockServiceB.execute(anyObject[ClassA])).thenReturn(Future{resultB})
when(mockServiceB.execute(anyObject())).thenReturn(Future{resultB})
when(mockServiceB.execute(anyObject)).thenReturn(Future{resultB})
when(mockServiceB.execute(any)).thenReturn(Future{resultB})
when(mockServiceB.execute(any, Some(3))).thenReturn(Future{resultB})
when(mockServiceB.execute(any[ClassA], Some(3))).thenReturn(Future{resultB})
All unfortunately to no avail. The only thing that changes is the number of expected and recorded matchers the exception refers to.
The weirdest thing for me though is that the mocking works perfectly for case A.

Use the idiomatic syntax of mockito-scala and all the stuff related to the default argument will be deal with by the framework
mockServiceB.execute(*) returns Future.sucessful(resultB)
if you add the cats integration it could reduce to just
mockServiceB.execute(*) returnsF resultB
more info here

You need to do this:
import org.mockito.ArgumentMatchersSugar._
when(mockServiceB.execute(any[ClassA], eqTo(Some(3)))).thenReturn(Future{resultB})
When you use any and the function receives multiple arguments you need to pass the other arguments that are not any with eq(something), hope this helps.
EDITED: My bad forgot the import and is eqTo and not eq

Related

In Mockito / Scala, verify method with unused varargs parameter

I have a method with this signature:
def foo(param1: => String, param2: (String, String)*)(implicit param3: Context): Unit
In my code, I call it as
foo("bar") // no varargs, implicit is in scope
In my Unit test, I am trying to verify the call:
verify(mock).foo(stringCaptor.capture())(any[Context])
This compiles, but produces a runtime exception:
Invalid use of argument matchers!
3 matchers expected, 1
recorded:
-> at
com.mycompany.MySpec$$anon$3.(MySpec.scala:88)
This
exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When
using matchers, all arguments have to be provided by
matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
For more
info see javadoc for Matchers class.
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers! 3 matchers expected, 1 recorded:
Yet if I try to match the varargs parameter, I get compilation errors:
verify(mock).foo(stringCaptor.capture(), any[Seq[(String, String)]])(any[Context])
Cannot resolve overloaded method 'foo'
What would be the syntax to match my method and verify the call correctly?
Note: answers to other questions suggest adding a dependency to mockito-scala, which I'd like to avoid
Update: adding a matcher for a tuple reduces the missing matchers from 1 to 2:
verify(mock).foo(stringCaptor.capture(),any[(String, String)])(any[Context])
Invalid use of argument matchers!
3 matchers expected, 2
recorded:
[...]
(it doesn't make a difference if I replace the ArgumentCaptor with anyString())
Another Update:
Ah, it seems the => String part causes the problem, didn't realize that I'm trying to match a lazy string here. Under the hoods, the compiler seems to turn my String into a Function0[String], but how can I match that?

MatchersException despite using any() and eq() in Test [Scala]

I have a method with the following signature:
def fetchCode[T](
seconds: Int,
client: String,
scope: String,
data: T,
retryLimit: Int = 10
)(implicit formats: Formats): String
and in my tests I'm trying to mock it as:
val accessCode: String = "CODE"
when(
mockService
.fetchCode[String](
any[Int],
any[String],
Matchers.eq(partner.name),
any[String],
any[Int]
)
).thenReturn(accessCode)
verify(mockService).fetchCode(
Matchers.any(),
Matchers.any(),
Matchers.eq(partner.name),
Matchers.any(),
Matchers.any()
)
Upon running this test, I still see the following errors:
Invalid use of argument matchers!
6 matchers expected, 5 recorded:
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
For more info see javadoc for Matchers class.
I don't see why this error crops up - I only need 5 matchers - one each for an argument, why are 6 expected?
As #Levi mentioned in his answer, you need to address all arguments the method gets, in order to use mocks. As you can see as part of your error message:
6 matchers expected, 5 recorded
What you need to do is to add any[Formats] in new paranthesis (exactly like your original method), and provide their the mock value:
when(
mockService
.fetchCode[String](
any[Int],
any[String],
Matchers.eq(partner.name),
any[String],
any[Int]
)(any[Formats])
).thenReturn(accessCode)
verify(mockService).fetchCode(
Matchers.any(),
Matchers.any(),
Matchers.eq(partner.name),
Matchers.any(),
Matchers.any()
)(any[Formats])
implicit formats: Formats is also passed as an argument, so mockito will need to be able to match it.

How to mock scala generic method

I have a traits(below simple versions) and I want to mock Foo.
trait MyTrait[A]
trait Foo {
def bar[T: MyTrait](id:Int, data: T, other:Option[String] = None): String
}
I tried:
implicit val myTrait = new MyTrait[String] {}
val src = mock[Foo]
when(src.bar(any(),any(),any())).thenReturn("ok")
src.bar(1, "some", None)
It fails with:
Invalid use of argument matchers! 4 matchers expected, 3 recorded
How to mock this kind of method?
Mockito does not play well with scala code. What happens in your case is that
notify.bar(any(), any(), any()) has to be invoked inside when(), but type of the bar method is unknown, so when scalac is looking-up implicits there are possibly several instances of Writes that fit here (becuase all of them do).
You can do something like this to make it work:
when(src.bar[T](any(),any(),any())).thenReturn("ok")
Edit
Following your edit, i think you should reconsider usage of mockito in the first place. Here's what happens:
Foo has the following signature after desugaring
trait Foo {
def bar[T](id:Int, data: T, other:Option[String] = None)(implicit ev: MyTrait[T]): String
}
I don't know if you are aware how does mockito work, but here is a quick explanation why (from what i can tell) this error happens:
at runtime method bar has the following "signature" (due to type erasure):
bar(id: Int, data: Object, other: Option[Object], ev: MyTrait[Object])
when(src.bar[T](any(),any(),any())).thenReturn("ok") actually invokes this method on a proxy object and registers "matchers", but ev is passed myTrait instead of a matcher, so i guess this violates some constraints of the library
As side-note: usually mocking is not that hard and you can simply implement a "mocked" trait without any help from mockito or other similar library.
The syntax [T : MyTrait] is sugar to add (implicit typeClass: MyTrait[T]) as a second set of arguments, so basically you're missing an argument matcher as the error states
So if you do
val src = mock[Foo]
when(src.bar(any(),any(),any())(any())).thenReturn("ok")
it works as expected
BTW, this is a bit of self promotion but I just published a library called mockito-scala that improves the mockito syntax for Scala, is part of the mockito ecosystem so hopefully should become the default when working with Scala, you can find it here https://github.com/mockito/mockito-scala with the information to get the dependency and what problems does it actually solves.

Mock is returning stubbed result for arbitrary param

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.
I think this is simply the manifestation that, in an acceptance specifications, there are no exceptions to signal failed expectations. So you you have:
def test = {
1 === 2
1 === 1
}
Then test is going to pass because only the last value will be kept as the test result. You can change this behaviour by either chaining expectations:
def test = {
(1 === 2) and
(1 === 1)
}
Or by mixing in the Specification the ThrownExpectations trait:
import org.specs2.Specification
import org.specs2.matcher.ThrownExpectations
import org.specs2.mock.Mockito
class MySpec extends Specification with ThrownExpecations with Mockito {
...
}

Matching any parameterless function as an argument in scala Mockito

I'm trying to verify the following method gets called using Mockito:
class Notifier {
def forward(request: ServletRequest)(onFailure: => Unit) : Unit
}
Here's the verification on a mock:
val notifier = mock[Notifier]
there was one(notifier).forward(any[ServletRequest])(any[() => Unit])
And I get the exception:
The mock was not called as expected:
Invalid use of argument matchers!
3 matchers expected, 2 recorded.
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
I know this is caused by the last parameterless function. How can I perform a verify properly here?
Could you try Function0[Unit] ?
there was one(notifier).forward(any[ServletRequest])(any[Function0[Unit]])