0

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.

Mario Galic
  • 47,285
  • 6
  • 56
  • 98
Niko
  • 616
  • 4
  • 20
  • Can you verify that it is working if you do not assign a default value to limit? (using what `@MarioGalic` posted as a comment). – second Jul 31 '19 at 14:10
  • @second It's not that easy.... I would have to change virtually every invocation in the code base... – Niko Jul 31 '19 at 14:12
  • Just use an isolated test (like the one in your question) as an example and test it out. If I understand it correctly the problem might be the internal handling of default values in scala, which refer to some `auto generated` methods that your mock does not cover. – second Jul 31 '19 at 14:13
  • 1
    Refer to this (https://stackoverflow.com/questions/25115329/verifying-mocked-object-method-calls-with-default-arguments) to get some more details – second Jul 31 '19 at 14:23

2 Answers2

3

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

ultrasecr.eth
  • 1,437
  • 10
  • 13
  • If you use it like this, that is no control to the inputs, and he wants to do a different thing based on the Option[Int] – Pedro Correia Luís Jul 31 '19 at 14:38
  • In the code snippet he only seem to care about the first parameter... in any case, there is nothing in my examples stopping him to modify the shape and number of marchers to fulfil his requirements – ultrasecr.eth Jul 31 '19 at 18:05
1

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

Pedro Correia Luís
  • 1,085
  • 6
  • 16
  • This does not even compile. The error is `expected Option[Int] but found Boolean`. The code is exactly the one you attached. – Niko Jul 31 '19 at 13:56
  • @Niko Try `ArgumentMatchers.eq(Some(3))`, or `any[Option[Int]]`. – Mario Galic Jul 31 '19 at 13:57
  • @MarioGalic It's still not working. The error changed to `Invalid use of argument matchers! 3 matchers expected, 2 recorded: -> at RandomServiceSpec.$anonfun$new$12(RandomServiceSpec.scala:147) -> at RandomServiceSpec.$anonfun$new$12(RandomServiceSpec.scala:147)` – Niko Jul 31 '19 at 13:59