Can view constrained Scala methods be mocked with Mockito and Specs2?

I ran into a problem with mocking methods that have view constraints on the type of their parameters using Mockito and Specs2. Simply put, because view binding translates to an additional implicit argument to a method, Mockito cannot match the call described by the wait to the actual arguments received by the mock:

For example:

//Receiver.scala
class Receiver {
  def methodWithViewBound[T <% WrappedString](w : T) : Unit = {
    //noop!
  }
}

//WrappedString.scala
class WrappedString(val wrapped : String) {

}

//TestMockedMethodWithViewBound.scala
import org.specs2.mutable._
import org.specs2.specification._
import org.specs2.mock._
import org.mockito.Matchers

class TestMockedMethodWithViewBound extends Specification with Mockito {

  implicit def wrapString(s : String) : WrappedString = new WrappedString(s);
  implicit def unwrapString(w : WrappedString) : String = w.wrapped;

  "Mockito" should {
    "Allow mocking of methods whose argument types include a view bound, using a matcher" in {
      val receiver = mock[Receiver]
      receiver.methodWithViewBound("Testing")
      there was one(receiver).methodWithViewBound(Matchers.eq("Testing")) 
    }


    "Allow mocking of methods whose argument types include a view bound, using an argument literal" in {
      val receiver = mock[Receiver]
      receiver.methodWithViewBound("Testing")
      there was one(receiver).methodWithViewBound("Testing")
    }
  }
}

      

The result of this gives:

[15:18:46] [tim@ahtanum ../tim/Projects/MockitoTest] $ sbt test
[info] Set current project to Mockito View Bounds Test (in build file:/home/tim/Projects/MockitoTest/)
[info] Compiling 1 Scala source to /home/tim/Projects/MockitoTest/target/scala-2.9.1/test-classes...
[info] Mockito should
[error] x Allow mocking of methods whose argument types include a view bound
[error]     The mock was not called as expected: 
[error] Invalid use of argument matchers!
[error] 2 matchers expected, 1 recorded.
[error] This exception may occur if matchers are combined with raw values:
[error]     //incorrect:
[error]     someMethod(anyObject(), "raw String");
[error] When using matchers, all arguments have to be provided by matchers.
[error] For example:
[error]     //correct:
[error]     someMethod(anyObject(), eq("String by matcher"));
[error] 
[error] For more info see javadoc for Matchers class. (TestMockedMethodWithViewBound.scala:12)
[info]  
[info]  
[info] Total for specification TestMockedMethodWithViewBound
[info] Finished in 175 ms
[info] 1 example, 1 failure, 0 error
[error] Failed: : Total 1, Failed 1, Errors 0, Passed 0, Skipped 0
[error] Failed tests:
[error]     TestMockedMethodWithViewBound
[error] {file:/home/tim/Projects/MockitoTest/}default-3adcf2/test:test: Tests unsuccessful
[error] Total time: 7 s, completed 07-Mar-2012 15:19:47
[15:19:47] [tim@ahtanum ../tim/Projects/MockitoTest] $ sbt test
[info] Set current project to Mockito View Bounds Test (in build file:/home/tim/Projects/MockitoTest/)
[info] Compiling 1 Scala source to /home/tim/Projects/MockitoTest/target/scala-2.9.1/test-classes...
[info] Mockito should
[error] x Allow mocking of methods whose argument types include a view bound, using a matcher
[error]     The mock was not called as expected: 
[error] Invalid use of argument matchers!
[error] 2 matchers expected, 1 recorded.
[error] This exception may occur if matchers are combined with raw values:
[error]     //incorrect:
[error]     someMethod(anyObject(), "raw String");
[error] When using matchers, all arguments have to be provided by matchers.
[error] For example:
[error]     //correct:
[error]     someMethod(anyObject(), eq("String by matcher"));
[error] 
[error] For more info see javadoc for Matchers class. (TestMockedMethodWithViewBound.scala:12)
[error] x Allow mocking of methods whose argument types include a view bound, using an argument literal
[error]     The mock was not called as expected: 
[error] Argument(s) are different! Wanted:
[error] receiver.methodWithViewBound(
[error]     "Testing",
[error]     ($anonfun$apply$mcV$sp$2) <function1>
[error] );
[error] -> at TestMockedMethodWithViewBound$$anonfun$1$$anonfun$apply$6$$anonfun$apply$2.apply$mcV$sp(TestMockedMethodWithViewBound.scala:22)
[error] Actual invocation has different arguments:
[error] receiver.methodWithViewBound(
[error]     "Testing",
[error]     ($anonfun$apply$7) <function1>
[error] );
[error] -> at TestMockedMethodWithViewBound$$anonfun$1$$anonfun$apply$6.apply(TestMockedMethodWithViewBound.scala:21)
[error]  (TestMockedMethodWithViewBound.scala:19)
[info]  
[info]  
[info] Total for specification TestMockedMethodWithViewBound
[info] Finished in 325 ms
[info] 2 examples (+1), 2 expectations (+1), 2 failures (+1), 0 error
[error] Failed: : Total 2, Failed 2, Errors 0, Passed 0, Skipped 0
[error] Failed tests:
[error]     TestMockedMethodWithViewBound
[error] {file:/home/tim/Projects/MockitoTest/}default-3adcf2/test:test: Tests unsuccessful
[error] Total time: 7 s, completed 07-Mar-2012 15:23:05

      

... has anyone encountered this issue before, or have any way of mocking methods with view constraints or implicit parameters using specs2?

Thank,

Tim

+3


source to share


1 answer


Tim, I've added the ability to check the converted parameters against the latest 1.9-SNAPSHOT spec2.

This is still experimental since I don't understand which of the unwanted effects might arise.



One thing, for example, is that any Function1 parameter will now be checked as ok by default, because Mockito cannot know which functions are implicit conversions and which are "regular" parameters.

+1


source







All Articles