Question

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?

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top