Reputation: 43
I have an Akka actor that works with a message containing a future. Here is a simplified version of it:
case class MyMessage(s: Future[String])
class MyWorker extends Actor {
override def receive: Receive = {
case MyMessage(future) =>
future onComplete {
case Success(s) => sender ! s
case Failure(e) => throw e
}
}
}
I am using TestActorRef to test it in specs2, but when I write a spec like this:
class MyWorkerSpec extends Specification with Mockito {
val worker = TestActorRef(new MyWorker)
"MyMessage" should {
"return the string from a successful result" in {
val message = MyMessage(Future("test"))
val result = worker ? message
result.value.get must_== Success("test")
}
}
}
...then it fails with NoSuchElementException: None.get
, and the Akka system complains about dead letters.
Figuring that this is probably because it isn't waiting for the future to complete, I decided to try mocking the future and stubbing the onSuccess
method. I'm not sure how to do this, though, because the func
argument is evidently an Any
.
class MyWorkerSpec extends Specification with Mockito {
val worker = TestActorRef(new MyWorker)
"MyMessage" should {
"return the string from a successful result" in {
val mockFuture = mock[Future[String]]
mockFuture.onComplete(any[Try[String] => String]) answers {
func => {
func(Success("test"))
}
}
worker ! MyMessage(mockFuture)
}
}
}
How does one mock a future like this? Or is there a better way to do it?
Upvotes: 3
Views: 4221
Reputation: 7466
I don't think there is any mocking required here.
1- How about creating your Future
like this: MyMessage(Future.successful("test"))
, that way it is completed when you create it.
2- You should wait for your actor to reply before calling value
on result
:
val result = worker ? message
Await.result(result, duration) must_== Success("test")
See: http://www.scala-lang.org/api/current/index.html#scala.concurrent.Await$
3- Sending an instance of Future
to an actor sounds like a terrible idea to me.
Upvotes: 4