Mauro Palsgraaf
Mauro Palsgraaf

Reputation: 237

Scalamock: Mocking a generic case class results in type mismatch

I'm using Mongodb as persistence in my application and I'm currently writing test for my code. My CUT looks as following

implicit def storageHandler[M[_]: Monad](
    implicit mongoDatabase: MongoDatabase
) = new Storage.Handler[M] {
    override def store(order: Order): M[Unit] = Monad[M].pure {
      val collection: MongoCollection[Document] = mongoDatabase.getCollection("order")

      val document: Document = Document(order.asJson.toString)

      collection.insertOne(document).subscribe((x: Completed) => ())
   }
}

My mock is getting properly injected by using implicits. I'm mocking the getCollection call which on it's own should result in another mock, this time of type

MongoCollection[org.mongodb.scala.bson.collection.immutable.Document]

So what I'm doing is the following

val mongoCollection: MongoCollection[Document] = mock[MongoCollection[Document]]

(mongoDatabase.getCollection[Document] _).expects("order").once().returning(mongoCollection)

But this result in the following error

type mismatch;
[error]  found   : com.mongodb.async.client.MongoCollection[TResult]
[error]  required: com.mongodb.async.client.MongoCollection[org.mongodb.scala.bson.collection.immutable.Document]
[error]  val mongoCollection: MongoCollection[Document] = mock[MongoCollection[Document]]

TResult is the generic parameter from the mongoCollection, which looks like this:

case class MongoCollection[TResult](private val wrapped: JMongoCollection[TResult]) { 
.... 
}

It seems that the generic parameter is not properly "adjusted" (I'm not sure how to call it) to Document

Upvotes: 4

Views: 1968

Answers (1)

Philipp
Philipp

Reputation: 967

Specifying the type parameter upfront should work, or, if your interface is fully abstract, you can use a Proxy mock for that:

import org.scalamock.scalatest.MixedMockFactory
import org.scalatest.{FlatSpec, Matchers}

import scala.reflect.ClassTag

class Issue170Test extends FlatSpec with Matchers with MixedMockFactory {
  behavior of "ScalaMock"

  it should "mock this" in {
    class Foo[T: ClassTag]
    "val m = mock[Foo[Nothing]]" should compile // this one fails :(
  }

  trait TotallyAbstract[T] {
    def foo: Int
    def bar: T
  }

  it should "work with this workaround" in {
    class Foo[T: ClassTag]
    abstract class Foo2 extends Foo[Int] // workaround: specify type parameter
    "val m = mock[Foo2]" should compile
    "val m2 = Proxy.mock[TotallyAbstract[Int]]" should compile
  }
}

Upvotes: 1

Related Questions