Introduction to mockito-scala — Part 2

Bruno Bonanno
5 min readAug 8, 2018

--

This article series was written for the version 0.x.x of mockito-scala, and while the technical details and reasoning behind the new features still holds true, some parts of the API were changed from 1.x.x, so I strongly recomend to have a read to the README where the changes are explained.

It’s also worth to check said README to discover the new features introduced in 1.x.x

In the first article we introduced the library and its improvements over the Java Mockito API.

Now we will see how the ArgumentMatchers are also improved by it

The first thing to notice is that we have the trait org.mockito.ArgumentMatchersSugar which again provides all the Matchers available in VanillaMockito plus a few more, it also improves the syntax for many of them.

It’s companion object also extends the trait, so if you don’t want to mix-it-in you can access them through it.

Naming clashes

If you’re like me, the first thing that would have give you problems with the matchers is the eq matcher, as you have to do a specific import alias to overcome the fact that eq is a method that already exists in every Scala object for doing reference equality, so basically you end up doing something like

import org.mockito.ArgumentMatchers.{eq => eqTo, _}

Over and over again, which I found really annoying…

So to fix that, the matcher method exposed by ArgumentMatchersSugar is already called eqTo[T] so you don’t have to bother about it.

Type inference and parenthesis

Another thing I found a bit cumbersome is that the Java API is inconsistent regarding when you can leave the parenthesis off or not, and wether you have to be explicit with the type or not, i.e. if you use any without parenthesis nor [Type] it will fail to compile with an error like

when(myMock.myMethod(any, any) thenReturn result------------Error:(85, 46) polymorphic expression cannot be instantiated to expected type;
found : [T]()T
required: String
when(myMock.myMethod(any, any) thenReturn result

So in that particular case you could fix it by either writing any() or any[String] or anyString and its variants with explicit parenthesis.

Similar things happen with many other methods around the VanilaMockito API, so, to overcome this problem and make the API more consistent, error-free and readable is that all the parameterless methods exposed by mockito-scala do not require parenthesis at all, making your code less likely to fail because you forgot a bloody parenthesis or a type, so the line when(myMock.myMethod(any, any) thenReturn result will actually work as expected.

Null matchers

Null matchers are marked as deprecated in mockito-scala, as you shouldn’t be using nulls anywhere in a decent Scala codebase, so the idea is to caught your attention to that with the compiler warning

Function matchers

There is a new matcher called function0 that allows you to test equality over no-args functions, the idea is that you could write something like

class Foo {
def iHaveFunction0[T](v: () => T): T = v()
}
val aMock = mock[Foo]

aMock.iHaveFunction0(() => "meh")

verify(aMock).iHaveFunction0(function0("meh"))

And so verify that your mock got called with a function that somehow returns the expected value.

Value class matchers

All right, you can read more about value classes here, but basically value classes only exist at compile time, to help us use the compiler to type check stuff -and also to make the code more explicit/readable- that otherwise would be simple, meaningless, types like an Int, String, etc without paying the overhead of creating this simple, stateless wrapper objects.

The fact that they don’t exist in runtime (and also that you can’t pass null when a value class is expected, as they are treated as values) makes them particularly annoying to use with VanillaMockito

What you have to do if you are using Matchers is to put them inside an instance of the value class itself, e.g. if we were using eqTo then we would have to do something like when(myMock.myMethod(MyValueClass(eqTo(someValue)) thenReturn <something> instead of when(myMock.myMethod(eqTo(MyValueClass(someValue))) thenReturn <something>

Which reads a bit odd, and it’s so anti-natural that if you don’t find that solution in stack overflow you could spend a long time trying to get them working.

What we want to achieve is to avoid as much of that boilerplate as we can, for this we use a combination of Macros and Type Classes (in the Scala docs they are called implicit macros)

So, given a value class case class MyValueClass(v: String) extends AnyVal what we want is a magic thing that constructs an instance of MyValueClass wrapping the matcher we want to use (currently only any and eqTo are supported)

This is where macros can help us, so we defined the trait

trait ValueClassMatchers[T] {  def anyVal: T  def eqToVal(v: Any): T}

And we want a macro that given a user type, in this case MyValueClass it inspects it (it’s like doing reflection but at compile time) and creates an implementation that looks like (I’ve simplified the code for readability)

new ValueClassMatchers[MyValueClass] {
def anyVal: MyValueClass = new MyValueClass(ArgumentMatchers.any[String]())

def eqToVal(v: Any): MyValueClass = new MyValueClass(ArgumentMatchers.eq[String](v))
}

Now, how do we get that instance tailored for our type (or how the compiler knows for what type it needs to create this), well this is where the TypeClass comes into play

For example, if you look at the anyVal[T] method in the ArgumentMatchersSugar trait, it has the following signature

def anyVal[T](implicit valueClassMatchers: ValueClassMatchers[T]): T = valueClassMatchers.anyVal

So basically when we do anyVal[MyValueClass] in our test code, the compiler will look for an implicit instance of the type ValueClassMatchers[MyValueClass]

In order to solve the implicit lookup, the companion object of ValueClassMatchers has the following method

implicit def materializeValueClassMatchers[T]: ValueClassMatchers[T] = macro materializeValueClassMatchersMacro[T]

That acts as an implicit factory for instances of that TypeClass, in where the actual definitions/instances are created by the macro.

So with all of that we get to a point where we can now write something like this (notice that for this matchers we must provide the type)

class Foo {
def valueClass(v: ValueClass): String = v.v
}
when(aMock.valueClass(anyVal[ValueClass])) thenReturn "mocked!"aMock.valueClass(ValueClass("meh")) shouldBe "mocked!"verify(aMock).valueClass(eqToVal[ValueClass]("meh"))

And it works!

So far those are the only 2 matchers that support value classes (anyVal[T] and eqToVal[T]) as I couldn’t think valid use-cases for the others, but if you need another one just open an issue in github and we’ll try to get it working.

That’s it, thanks for reading and I hope you enjoy the library!

Please check Part 3 for more exciting features

--

--