Skip to content
[Scala] Akkaの単体テストはwith ImplicitSenderを忘れやすい
java-tips-scala-tips
2019-11-28

普段Akkaをごりごり使う訳ではないので、こういうTips的なことはすっかり忘れてひとしきり悩む。

package my_test

import akka.actor.{Actor, ActorRef}
import my_test.CalculatorActor.Add

class CalculatorActor extends Actor {
  override def receive: Receive = {
    case Add(val1,val2) =>{
      val ret = val1+val2
      sender() ! ret  // 計算結果を返して
    }
  }
}

object CalculatorActor {
  case class Add(val1:Int,val2:Int)
}
package my_test

import akka.actor.{Actor, ActorRef}
import my_test.CalculatorActor.Add

class CalculatorActor extends Actor {
  override def receive: Receive = {
    case Add(val1,val2) =>{
      val ret = val1+val2
      sender() ! ret  // 計算結果を返して
    }
  }
}

object CalculatorActor {
  case class Add(val1:Int,val2:Int)
}
package my_test

import java.util.concurrent.TimeUnit
import akka.actor.{ActorSystem, Props}
import akka.routing.RoundRobinPool
import akka.testkit.{ImplicitSender, TestKit}
import org.scalatest.{BeforeAndAfterAll, fixture}
import scala.concurrent.duration.Duration

class CalculatorSpec extends TestKit(ActorSystem("testBatch")) with fixture.FreeSpecLike
  with fixture.TestDataFixture with BeforeAndAfterAll {
  "計算機" - {
    "加算" in { td => {
      val actor = system.actorOf(Props[CalculatorActor].withRouter(RoundRobinPool(2)))
      actor ! CalculatorActor.Add(1, 2)  // 1+2を計算機に送って
      val ret = receiveOne(Duration(10, TimeUnit.SECONDS))
      assert(ret == 3,"計算エラー")  //  結果が3かを確認する
      println(ret)
    }
    }
  }

  override protected def afterAll() {
    super.afterAll()
    Thread.sleep(30 * 1000)
    TestKit.shutdownActorSystem(system, Duration(10, TimeUnit.MINUTES))
  }
}
package my_test

import java.util.concurrent.TimeUnit
import akka.actor.{ActorSystem, Props}
import akka.routing.RoundRobinPool
import akka.testkit.{ImplicitSender, TestKit}
import org.scalatest.{BeforeAndAfterAll, fixture}
import scala.concurrent.duration.Duration

class CalculatorSpec extends TestKit(ActorSystem("testBatch")) with fixture.FreeSpecLike
  with fixture.TestDataFixture with BeforeAndAfterAll {
  "計算機" - {
    "加算" in { td => {
      val actor = system.actorOf(Props[CalculatorActor].withRouter(RoundRobinPool(2)))
      actor ! CalculatorActor.Add(1, 2)  // 1+2を計算機に送って
      val ret = receiveOne(Duration(10, TimeUnit.SECONDS))
      assert(ret == 3,"計算エラー")  //  結果が3かを確認する
      println(ret)
    }
    }
  }

  override protected def afterAll() {
    super.afterAll()
    Thread.sleep(30 * 1000)
    TestKit.shutdownActorSystem(system, Duration(10, TimeUnit.MINUTES))
  }
}

「1+2を計算機に送って、結果をもらって3かどうか確認する」はこれでよいだろう。と思っていると

[INFO] [11/28/2019 23:10:18.160] [testBatch-akka.actor.default-dispatcher-4] [akka://testBatch/deadLetters] Message [java.lang.Integer] from Actor[akka://testBatch/user/$a/$a#-158423933] to Actor[akka://testBatch/deadLetters] was not delivered. [1] dead letters encountered. If this is not an expected behavior, then [Actor[akka://testBatch/deadLetters]] may have terminated unexpectedly, This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
[INFO] [11/28/2019 23:10:18.160] [testBatch-akka.actor.default-dispatcher-4] [akka://testBatch/deadLetters] Message [java.lang.Integer] from Actor[akka://testBatch/user/$a/$a#-158423933] to Actor[akka://testBatch/deadLetters] was not delivered. [1] dead letters encountered. If this is not an expected behavior, then [Actor[akka://testBatch/deadLetters]] may have terminated unexpectedly, This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.

でDead Letterになって届かずエラー。

ひとしきり悩んで本を読み直すと 単に

class CalculatorSpec extends TestKit(ActorSystem("testBatch")) with fixture.FreeSpecLike with fixture.TestDataFixture with ImplicitSender with BeforeAndAfterAll {

単に with ImplicitSender が足りないだけだった。。。

見えにくい約束事が多いのは望ましくはないものの、昔と比べれば全然訳のわからない約束事は減ったので今のほうが全然よい。Akkaなんて15年前にあったら本当にありがたいと思うし。というものの少なくなって欲しいとは思う。

関係ないが ScalaTest は FreeSpec が日本人向きだと思うけどなー。変な擬似英語に悩まずに済むし、表形式の結果に加工しやすいので表好きな日本人向きだと思うし。