在Akka中使用TestActorRef时,如何在没有用户监护人关闭的情况下检测错误和异常?

时间:2015-03-02 11:46:02

标签: scala akka akka-testkit

使用TestActorRef执行同步测试时(根据Testing Actor Systems的建议),有时需要测试异常是否抛出,与预期的任何其他测试分开要传回的消息等。

如何在单元测试中可靠地完成这项工作?

This answer显示了如何使用EventFilter为异常添加处理程序。但是,此方法不适用于Throwable的{​​{1}}。

以下是示例代码:

Error

此代码存在多个问题,但主要问题是第三个测试始终失败,因为用户监护人失败,并在日志记录输出中显示以下消息:

import akka.actor.{Actor, ActorLogging, ActorSystem, Props} import akka.event.Logging import akka.testkit.{EventFilter, ImplicitSender, TestKit, _} import com.typesafe.config.{Config, ConfigFactory} import org.scalatest.{FlatSpec, Matchers} import scala.collection.mutable object GreetingProtocol { case class Greet(msg: String) case object GreetWithNPE case object GreetWithError } class ErrorLogger() { val errors = mutable.ListBuffer[Logging.Error]() val filter = EventFilter.custom { case e: Logging.Error => errors += e false } } class Greeter extends Actor with ActorLogging { import GreetingProtocol._ def receive = { case Greet(who) => log.info(s"Hello $who") case GreetWithError => ??? case GreetWithNPE => throw new NullPointerException("NPE") } } class GreetingSpec extends FlatSpec with Matchers { import GreetingProtocol._ def testEventListener(theFilter: EventFilter) = Props(new TestEventListener { addFilter(theFilter) }) def akkaConfiguration: Config = ConfigFactory.parseString( """ |akka { | loglevel = DEBUG | actor.debug { | receive = on | lifecycle = on | event-stream = on | } | remote { | log-sent-messages = on | log-received-messages = on | } |} | """.stripMargin) "a normal greeting" should "cause the test to succeed" in new TestKit(ActorSystem("test", akkaConfiguration)) with ImplicitSender { val errorLogger = new ErrorLogger() system.eventStream.subscribe(system.actorOf(testEventListener(errorLogger.filter), "ErrorListener"), classOf[Logging.Error]) filterEvents(errorLogger.filter)({ val greeter = TestActorRef[Greeter]("Greeter") greeter ! Greet("Bob") }) shutdown() withClue("errors logged") { errorLogger.errors should have length 0 } } "a NullPointerException" should "be caught by the testing framework and not make the test succeed" in new TestKit(ActorSystem("test", akkaConfiguration)) with ImplicitSender { val errorLogger = new ErrorLogger() system.eventStream.subscribe(system.actorOf(testEventListener(errorLogger.filter), "ErrorListener"), classOf[Logging.Error]) filterEvents(errorLogger.filter)({ val greeter = TestActorRef[Greeter]("Greeter") greeter ! GreetWithNPE }) shutdown() withClue("errors logged") { errorLogger.errors should have length 1 } } "an Error" should "be caught by the testing framework and not make the test succeed" in new TestKit(ActorSystem("test", akkaConfiguration)) with ImplicitSender { val errorLogger = new ErrorLogger() system.eventStream.subscribe(system.actorOf(testEventListener(errorLogger.filter), "ErrorListener"), classOf[Logging.Error]) filterEvents(errorLogger.filter)({ val greeter = TestActorRef[Greeter]("Greeter") greeter ! GreetWithError }) shutdown() withClue("errors logged") { // Fails because the user guardian is shut down and the ErrorListener is gone with it errorLogger.errors should have length 1 } } }

第三种情况可以做些什么,以便测试成功(即错误记录在错误列表中)?

还有另外两个小问题:

  • 需要shutdown()调用,因为没有明显的方法可以等待事件监听器处理事件,并且任意超时甚至更加不可能
  • 实际上不需要filterEvents()调用,但所有示例似乎都使用它,为什么?

版本:

  • Scala 2.11.4
  • Akka 2.3.7
  • Scalatest 2.2.2

0 个答案:

没有答案