Future のテスト

Future は、処理がブロックされず、いずれ答えを返してくれる便利なものですが、 テストコードのように結果を検証したい場合は処理の完了を待つ必要があります。

下のサンプルコードでは、Future を Await.ready を使って、実行が完了するのを待ちます。 Await.ready に指定した時間が経過しても処理が完了しない場合は例外がスローされてテストケースは 失敗します。 実行が完了した場合は、Future.value.get で処理結果を取得します。

package jp.pigumer.akka

import akka.actor.{ActorSystem, Props}
import akka.event.Logging
import akka.util.Timeout
import org.specs2.mutable.Specification
import org.specs2.specification.Scope

import scala.concurrent.duration._
import akka.pattern._

import scala.concurrent.Await

class FutureSpec extends Specification {

  trait WithFixture extends Scope {
    implicit val system = ActorSystem("FutureSpec")
    implicit val logger = Logging(system, classOf[WithFixture])

    val actor = system.actorOf(Props[SlowActor])
  }

  "Future Test" should {
    "Success" in new WithFixture {
      implicit val timeout: Timeout = 1 seconds

      logger.info("start")
      val e = actor ? 1
      Await.ready(e, 60 minutes)
      logger.info("finish")

      e.value.get.fold(
        cause ⇒ {
            logger.error(cause, "failed")
            failure
          },
        _ ⇒ success
      )
    }

    "Timeout" in new WithFixture {
      implicit val timeout: Timeout = 1 seconds

      logger.info("start")
      val e = actor ? 4
      Await.ready(e, 5 seconds)
      logger.info("finish")

      e.value.get.fold(
        cause ⇒ {
          logger.error(cause, "failed")
          success
        },
        _ ⇒ failure
      )
    }
  }
}