4

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

Mauro Palsgraaf
  • 237
  • 3
  • 13

1 Answers1

1

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
  }
}
Philipp
  • 967
  • 6
  • 16