I have a trait
trait Writer[T <: Attribute] {
def read(boundingBox: BoundingBox): Future[List[T]]
}
and a case class
case class WriterImpl[T <: Attribute]()(implicit manifest: Manifest[T]) extends Writer[T] with LazyLogging {
override def read(boundingBox: BoundingBox): Future[List[T]] = {
}
..
}
In the Test class I want to mock the method read()
I tried this with exact values
val writer = mock[WriterImpl[Attrib]]
when(writer.read(new BoundingBox(41.90178412, 41.8798685, -87.62687021, -87.64884287)))
.thenReturn(Future.successful(scala.collection.immutable.List(list)))
verify(writer).read(new BoundingBox(41.90178412, 41.8798685, -87.62687021, -87.64884287))
also tried
val writer = mock[WriterImpl[Attrib]]
when(writer.read(ArgumentMatchers.any()))
.thenReturn(Future.successful(scala.collection.immutable.List(list)))
verify(writer).read(ArgumentMatchers.any())
Instead of calling the mock method it calls the actual method
CodePudding user response:
In the first example, the problem is you use 2 different BoundingBox
objects as parameters for the read
method, one for the when
method, and one for the verify
method. They will not match because at runtime they are different instances of the same BoundingBox
class. You should use the same object. Store it before the when
clause and then call verify
passing that same object.
I assume you just removed the obvious call to writer.read(...)
anywhere between the when
and verify
clauses. verify
expects at least one call to read
, otherwise it throws a "Wanted but not invoked: writerImpl.read(...); Actually, there were zero interactions with this mock.."
The second example should work, but you will still have the same issue if you'll try to check the result. You will result in 2 different instances of a Future
: once in the when
and once in the verify
. Again, at runtime, they are 2 different objects, so they will not match if you use :
result shouldBe Future.successful(scala.collection.immutable.List(new Attribute))
The output confirms the runtime sees 2 different instances:
Expected :Future(Success(List(org.scala.snippets.Test$Attribute@373052b5)))
Actual :Future(Success(List(org.scala.snippets.Test$Attribute@17207f5b)))
Again, you should store the Future
before when
and pass the same Future
to both when
and shouldBe
.
With these adjustments this should work. Now Checking the result of read
confirms the same Future
was returned from the call:
import Test.{Attribute, BoundingBox, WriterImpl}
import org.mockito.MockitoSugar
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec
import scala.concurrent.Future
class ProgramTest extends AnyWordSpec with MockitoSugar with Matchers {
"Program " should {
"return the mocked succf " in {
val succf = Future.successful(scala.collection.immutable.List(new Attribute))
val bb = new BoundingBox(41.90178412, 41.8798685, -87.62687021, -87.64884287)
val writer = mock[WriterImpl[Attribute]]
when(writer.read(bb)).thenReturn(succf)
val result = writer.read(bb)
verify(writer, times(1)).read(bb)
result shouldBe succf
}
}
}
Here's my build.sbt
in case you need it:
libraryDependencies = "org.scalatest" %% "scalatest" % "3.2.12" % Test
libraryDependencies = "org.scalatestplus" %% "scalacheck-1-16" % "3.2.12.0" % Test
libraryDependencies = "org.scalatestplus" %% "mockito-4-5" % "3.2.12.0" % Test
libraryDependencies = "org.mockito" % "mockito-core" % "4.6.1" % Test
libraryDependencies = "org.mockito" %% "mockito-scala" % "1.17.7" % Test