InvalidUseOfMatchersException when I am passing any string for my mock parameter - scala

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

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.

Mockito: 0 matchers expected, 1 recorded

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

Why does ScalaTest by default not enforce types when matching?

I was wondering why ScalaTest behaves differently compared to Specs2.
Specs2
"" must be equalTo 3
TestSpec.scala:11:26: type mismatch;
[error] found : Int(3)
[error] required: String
[error] "" must be equalTo 3
ScalaTest
3 should === ("r")
[info] Done compiling.
[info] TestTest:
[info] Dummy test
[info] - should fail *** FAILED ***
[info] "" did not equal 3 (PersistentTaskRuntimeTest.scala:21)
ScalaTest by default only fails at runtime, everything is compared as Any-to-Any.
There is the Supersafe plugin to get better checks (or TypeCheckedTripleEquals) but these feel like hacks as Specs2 just uses the scala compiler to require the types of the two values compared to be in a subtype/supertype relationship.
For reference this is the output when using TypeCheckedTripleEquals, mind the hacky CanEqual
TestTest.scala:21:7: types String and Int do not adhere to the type constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.CanEqual[String,Int]
[error] "" should === (3)
[error] ^
So what is the rationale behind this?
Less heavy for the scala compiler?
Less code to write for ScalaTest?
Less implicit magic (cryptic error messages)?
Pushing a commercial compiler plugin?
TypeCheckedTripleEquals is using generalised type constraints, for example, B <:< A in
implicit override def typeCheckedConstraint[A, B](implicit equivalenceOfA: Equivalence[A], ev: B <:< A): A CanEqual B
This is standard Scala functionality to enforce compile-time safety, and is used in many widespread Scala libraries. For example,
import org.scalactic.TypeCheckedTripleEquals
import org.scalatest._
class CompileTimeSafetySpec extends FlatSpec with Matchers with TypeCheckedTripleEquals {
"TypeCheckedTripleEquals" should "provide compile-time safety" in {
3 should === ("r")
}
}
gives compiler error
types Int and String do not adhere to the type constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.CanEqual[Int,String]
[error] 3 should === ("r")

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]])