Search code examples
scalajmockscalamock

scalamock: Wildcard argument match on subtype


In my class, I have two versions of a method. One takes an Exception, the other a String.

class Foo {
  def method(e: Exception) = ???
  def method(s: String) = ???
}

In JMock, I can mock a call to a method based on its type. Notice, I'm using a subtype of Exception to be specific about what I'm expecting in my test.

context.checking(new Expectations() {{              
    oneOf(mock).method(with(any(SubTypedException.class)));
}}

and in Scalamock, I can use a wildcard to match

(mock.method(_: Exception)).expects(*).once

The following doesn't compile when I try to match on a specific subtype (I realise this doesn't make sense in Scala).

// doesn't compile    
(mock.method(_: SubTypedException)).expects(*).once

How can I convert the with(any(SubTypesException.class)) in JMock to Scalamock? I can imagine using a predicate match (where), is that the way to go?

Edit: Thinking about it, the JMock with(any(SubTypedException)) is more about keeping the compiler happy and expressing intent. As I understand it, the Matcher is an IsAnything matcher so won't actually fail a test if a different type of exception is thrown.

So, it may be asking a bit much of Scalamock to both capture the intent and fail the test under the right circumstance. Bonus points in explaining how to do something like instanceOf in Scalamock.


Solution

  • First of all: The following does not compile, since the type ascription is only to help (static) overloading resolution. The line has nothing specific to Scalamock:

    (mock.method(_: SubTypedException))
    

    To test the runtime type of the argument you can use ArgThat which was introduced in ScalaMock 3.2.1 together with a helper function:

    import scala.reflect.ClassTag
    
    def typedArg[T, U : ClassTag]: ArgThat[T] = new ArgThat[T]({
      case x: U => true
      case _ => false
    })
    
    (mock.method(_: Exception)).expects(typedArg[Exception, SubTypedException])