0

I'm working on an existing code base with a wrapper class around Slick 2.1.0 (I know). This wrapper has a method named transaction that is a generic - it takes a (f: => T) (so it's pass-by-name). I need to mock this class for an unit test. We're also using Mockito 1.10.19 (again, I know), which won't let me mock a pass-by-name (I believe...). So I'm stuck implementing the underlying trait that this wrapper class is built on.

The immediate problem is this: I want to mock this transaction method so it does nothing. The code I'm testing passes in a (f: => Unit). So I want to implement this method to return a Future.Done. (Did I mention we're using Finagle and not Scala futures?) But this method is generic. How do I properly specialize?

This is my current attempt:

val mockDBM = new DatabaseManager {
    override def transaction[@specialized(Unit) T](f: => T): Future[T] = Future.value(f)
    def transaction(f: => Unit): Future[Unit] = Future.Done
}

Of course, I get a have same type after erasure error upon compilation. Obviously I have no idea how @specialized works.

What do I do? Maybe I can use Mockito after all? Or I need to learn what specializing a generic method actually means?

I found this, which probably contains the answer, but I have no formal background in FP, and I don't grok this at all: How can one provide manually specialized implementations with Scala specialization?

Community
  • 1
  • 1
jennykwan
  • 2,631
  • 1
  • 22
  • 33
  • Why do you need to specialize? Isn't overriding the `transcation` method on `DatabaseManager` enough to achieve what you want? – Yuval Itzchakov Jan 31 '17 at 09:52
  • I had to try it again because I'm questioning my sanity on this. The trait itself defines the generic method. I need to override it with my own generic. But I can only return `Future.Done` if the generic is for a `Unit` type. Hence the specialization. I'm sure I'm missing something. What is it? – jennykwan Jan 31 '17 at 10:03
  • So you want `Future.Done` instead of `Future.value(Unit)` ? – Yuval Itzchakov Jan 31 '17 at 10:09
  • `DatabaseManager` is a dependency I'm injecting to the class under test. I can't control the `f` that's being passed in. What I _want_ is to disregard `f` completely and return `Future.Done` regardless. If I run the `f` that's actually passed in, it will raise an exception, because in the class under test, `f` depends on an implicit that Slick provides, which my mock class doesn't have. I need to find a way to hack this such that `f` is not actually executed. – jennykwan Jan 31 '17 at 10:13

1 Answers1

2

@specialized doesn't let you provide specializations, it just generates its own. The answer provided in the linked question would require changing the signature. From the question it looks like you can't change it, in which case you are out of luck. If you can... you may still be out of luck, depending on how exactly this code is going to be called.

OTOH, the solution for "I want to disregard f, but can only return Future.Done if the generic is for a Unit type" is far simpler:

class Default[A] {
  var x: A = _
}
object Default {
  def apply[A]() = (new Default[A]).x
}

val mockDBM = new DatabaseManager {
  override def transaction[T](f: => T): Future[T] = {
    Future.value(Default(x))
  }
}

Assuming you need a successful future, but don't care about value, that is; if you just need any future, override def transaction[T](f: => T): Future[T] = Future.???.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • OMG. I'll be in the office shortly and will try this, but what does the underscore resolve to here? – jennykwan Jan 31 '17 at 15:38
  • No dice. Running Scala 2.11.7. I get `local variables must be initialized`. With `val` instead of `var` I get `unbound placeholder parameter`. :( – jennykwan Jan 31 '17 at 16:03
  • My team decided to cut bait on this and just smoke test manually. I will try this at some point tomorrow. Upvoting and accepting now! – jennykwan Feb 01 '17 at 00:17