Wrap argThat in a named function

833 Views Asked by At

Say I have something like this (VERY OVER-SIMPLIFIED):

case class Foo(bar: String)
val mockFnThatTakesFoo = mock[Foo => Unit]

def fooHasBarSetTo(expectedBar: String, foo: Foo): Boolean = {
  val actualBar = foo.bar
  actualBar shouldEqual expectedBar
  true
}

mockFnThatTakesFoo(argThat(fooHasBarSetTo("blah", _))) wasCalled once

This works. However, the assertion itself is a little bit convoluted and it could be made more readable.
I tried this:

val withFooHavingBarSetTo = (expectedBar: String) => argThat(fooHasBarSetTo(expectedBar, _))

//and then
mockFnThatTakesFoo(withFooHavingBarSetTo("blah")) wasCalled once

Much neater! but doesn't work :/

> [info] FooSpec:
[info] - should do stuff *** FAILED ***
[info]   org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers!
[info] 1 matchers expected, 2 recorded:
[info] -> at com.foo.FooSpec.argThat(FooSpec.scala:28)
[info] -> at com.foo.FooSpec.$anonfun$new$5(FooSpec.scala:204)

Any idea how can this be done?

1

There are 1 best solutions below

0
On

I believe Mockito is implemented using macro and it tracks positions where argThat and other Mockito methods are placed. For example if you try to create a variable like

    val blahBar = argThat(fooHasBarSetTo("blah", _))

You will get an exception "Misplaced or misused argument matcher detected here". So it is impossible to return argThat matcher from another method.

If you need to reuse mock matcher with different argument value I see only one possible solution like

    def mockCalledOnceWithFooHavingBar(expectedBar: String) {
      mockFnThatTakesFoo(argThat(fooHasBarSetTo(expectedBar, _))) wasCalled once
    }

    mockCalledOnceWithFooHavingBar("blah")
    mockCalledOnceWithFooHavingBar("bar")