Mocking scala method calls containing type parameters with context bounds

senjinhajrulahovic

Senjin Hajrulahovic

Posted on October 16, 2021

Mocking scala method calls containing type parameters with context bounds

In our example we will be looking at a very simple auditing mechanism. Every time a resource changes we want to store its previous and its new state as json.

While investigating the code base we come across a trait like this:

trait AuditLogHandler {
    def addAuditLog[A: Writes](previous: A, next: A)
            (implicit session: Session): Unit
}
Enter fullscreen mode Exit fullscreen mode

We find out that Writes is needed to create the json form of the object, and we notice that Session takes care of actually storing the values in the database.

After creating a class which utilizes an instance of the trait above we start to write tests. We decide to use mocking.

Our first attempt to mock the addAuditLog method will most likely look like this:

(auditLogHandler.addAuditLog(_: A,_: A)(_: Session))
    .expects(*, *, *).anyNumberOfTimes().returning(())
Enter fullscreen mode Exit fullscreen mode

which will result in the error message:

Unspecified value parameters: session: Session
Enter fullscreen mode Exit fullscreen mode

We scratch our heads in disbelief. How can it be unspecified if it is right there?! We think that our IDE got confused, which happens from time to time. So we decide to recompile it with sbt which gives us the same error.

After spending some time looking up the issue without results we analyze our dependencies. Their versions seem to be quite behind. Full of hope we update scalatest and other related dependencies just to see the same outcome.

Still:

Unspecified value parameters: session: Session
Enter fullscreen mode Exit fullscreen mode

Hopefully we eventually remember that A: Writes is just syntactic sugar for an implicit parameter of type Writes[A].

So:

def addAuditLog[A: Writes](previous: A, next: A)
        (implicit session: Session): Unit
Enter fullscreen mode Exit fullscreen mode

is actually:

def addAuditLog[A](previous: A, next: A)
        (implicit writes: Writes[A], session: Session): Unit
Enter fullscreen mode Exit fullscreen mode

After trying it out it proves to be the solution:

(auditLogHandler.addAuditLog(_: A, _: A)
    (_: Writes[Assembly], _: Session))
    .expects(*, *, *).anyNumberOfTimes().returning(())
Enter fullscreen mode Exit fullscreen mode

Looking at the solution we can't help but feel a bit irritated that it took us that much to figure out, while still being happy that we actually got it to work in the end.

đź’– đź’Ş đź™… đźš©
senjinhajrulahovic
Senjin Hajrulahovic

Posted on October 16, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related