How to implement a minimal mock of a polymorphic method in Scala?

Viewed 156

Say I have the following trait and class:

case class Result[A](
    header: String,
    data: A
)

trait WebClient {
  def doSomething[A : TypeTag](name: String): Future[Result[A]]
}

In this example, doSomething is the polymorphic method in question. How can I create a MockWebClient which implements WebClient and have minimal behavior? (The most minimal behavior being doing nothing.) Preferably, I don't want to return a Future.failed because the result shouldn't signify a failure, semantically. Also, I don't want to change the A type of Result[A] to be covariant or contravariant (i.e. +A or -A) because it doesn't make a lot of sense in the context.

Here's my best attempt (which still doesn't compile). It uses a generic class with a generic factory to simulate the return value of the doSomething method. However, I cannot find the correct relationship between A and B:

class MockWebClient[A](val factory: () => Result[A]) extends WebClient {
  override def doSomething[B >: A : TypeTag](name: String): Future[Result[B]] = {
    Future.successful(factory())
  }
}

Also, I have used mockito-scala, but it doesn't work because of type erasure. scalamock also seems interesting, but I would like to know if there is a way to make something similar to my solution work.

1 Answers

If you are sure data field will not be used in the test you could trick the compiler with null.asInstanceOf[A]

val mockWebClient = new WebClient {
  override def doSomething[A](name: String): Future[Result[A]] =
    Future.successful(Result(name, null.asInstanceOf[A]))
}

If A forms a Monoid you could do it in a type-safe manner with something like

import cats.Monoid
import cats.implicits._

trait WebClient {
  def doSomething[A: Monoid](name: String): Future[Result[A]]
}

val mockWebClient = new WebClient {
  override def doSomething[A: Monoid](name: String): Future[Result[A]] =
    Future.successful(Result(name, implicitly[Monoid[A]].empty))
}

mockWebClient.doSomething[String]("woohoo")
Related