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?
Related
I was trying to find out if I can use something like the any argument matcher for a method with type parameters:
when(store.getItems[Product](any[FilterParams]))
.thenReturn(allProducts)
When running the code with the above snippet, I get this error:
Invalid use of argument matchers!
2 matchers expected, 1 recorded
I guessed this would be because I passed an exact type parameter Product to the getItems method.
This does work when I pass in an actual FilterParams object:
when(store.getItems[Product](FilterParams()))
.thenReturn(allProducts)
Is there any argument matcher that I can use for the type parameter? Or is it counter-intuitive, because whenever we're calling a function with a type parameter, we have to pass the type parameter?
Edit:
Product here isn't Scala's built-in Product trait.
The function signature of the getItems method:
def getItems[T <: ItemType : universe.TypeTag](filterParams: FilterParams): List[T]
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.
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
I want my mock to be able to handle any input for the method
val redis = mock[RedisClient]
when(redis.scard(any[String])).thenReturn(Some("hello"))
The error:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers!
[info] 2 matchers expected, 1 recorded:
[info] -> at ..(SomeSpec.scala:123)
[info]
[info] This exception may occur if matchers are combined with raw values:
[info] //incorrect:
[info] someMethod(anyObject(), "raw String");
scard takes two parameters, of which one parameter is implicit:
// SCARD
// Return the number of elements (the cardinality) of the Set at key.
def scard(key: Any)(implicit format: Format): Option[Long] =
send("SCARD", List(key))(asLong)
If you don't specify the argument, Scala will provide one, which interferes with Mockito's ability to line up matchers with arguments.
See also: org.specs2.mock.Mockito matchers are not working as expected
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]])