0

i am using akka testkit and scalatests for running my test here is my code

class MyTest extends (ActorSystem("testsystem")) /*with AsyncWordSpec*/ with ImplicitSender with AnyWordSpecLike  with Matchers with BeforeAndAfterAll {
   "an actor test" must {
      val probe = TestProbe()
      val myActor1 = TestActorRef[MyActor]

      "send back messages " in {
        probe.send(myActor1,Found(id = "234"))
        probe.expectMsg(true)
        //i want to get the future value like this as well 
        val future = ask(myActor, Found(id = "234")).mapTo[Boolean]
        future onComplete {
            case Success(somevalue) => info("oncomplete returned result is " + somevalue)
            case Failure(ex) =>throw ex
        }
    }
}

class MyActor extends Actor {

  def receive: PartialFunction[Any, Unit] = {
    case Found(id) => 
      log.info("received message {}", id)
      sender() ! true
    case message =>
      unhandled(message)
  }
}

now the problem is the above code works fine but the future on complete part is sometime executed and sometimes its not when running the test for that i researched about async testing scala and try to implement the examples http://www.scalatest.org/user_guide/async_testing

for that i need to extend from any of the given classes there i chose AsyncWordSpec so that i can run the async tests and get the value of future every time but i am already extending from TestKit class i can not extend from the abstract class AsyncWordSpec so how can i get this to work?

Iva Kam
  • 932
  • 4
  • 13
swaheed
  • 3,671
  • 10
  • 42
  • 103

2 Answers2

0

The problem is that your future needs to be awaited to ensure that it is executed. Futures start evaluation at the moment of creation asynchronuously. That means main thread will not be blocked until the future completion - it will continue running. So, in your case there's two possibilities:

1)
test start
|
|_ _ _ _ _ _ _ _
future creation  \
|                |
|                | 
|                future completed, callback executed
test end
2) 

test start
|
|_ _ _ _ _ _ _ _ _ 
future creation   \
|                 |
|                 | 
|                 |
test end          |
executor shutdown X - future termination, no callback

In the second case, your callback is not run due to future termination as the test exits. To make this thing more predictable, you should block on your resulting future at the end of the test. You either can do it with test framework sugar or Await.result.

Iva Kam
  • 932
  • 4
  • 13
0

Some clarification:

Blocking the single thread running the test until a future completes is fine, there is no value in the test case being async. The test thread is separate from the threads/dispatchers inside Akka, where it would be problematic to block.

Blocking on completion is what the TestKit probes do when you expectMessage for example. Await.result is one way, Scalatest also has ScalaFutures which adds a decorator to Future called .futureValue and .whenReady, both of those also blocks the test thread until the future completes or a timeout is reached.

johanandren
  • 11,249
  • 1
  • 25
  • 30