加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

当akka actor在测试线程之外抛出异常时,没有使用scalatest

发布时间:2020-12-16 18:45:50 所属栏目:安全 来源:网络整理
导读:我有一个情况出现并咬我几次我正在测试一个Actor并且Actor意外地抛出一个异常(由于一个bug),但测试仍然通过.现在大多数情况下,Actor中的异常意味着无论测试验证是否都不正确,因此测试失败,但在极少数情况下这不是真的.异常发生在与测试运行器不同的线程中,因
我有一个情况出现并咬我几次我正在测试一个Actor并且Actor意外地抛出一个异常(由于一个bug),但测试仍然通过.现在大多数情况下,Actor中的异常意味着无论测试验证是否都不正确,因此测试失败,但在极少数情况下这不是真的.异常发生在与测试运行器不同的线程中,因此测试运行器对此一无所知.

一个例子是当我使用mock来验证一些依赖项被调用时,由于Actor代码中的错误,我在mock中调用了一个意外的方法.这导致模拟抛出一个异常,炸毁了演员而不是测试.有时这甚至可能导致下游测试因为Actor如何爆炸而神秘地失败.例如:

// using scala 2.10,akka 2.1.1,scalatest 1.9.1,easymock 3.1
// (FunSpec and TestKit)
class SomeAPI {
  def foo(x: String) = println(x)
  def bar(y: String) = println(y)
}

class SomeActor(someApi: SomeAPI) extends Actor {
  def receive = {
    case x:String  =>
      someApi.foo(x)
      someApi.bar(x)
  }
}

describe("problem example") {
  it("calls foo only when it receives a message") {
    val mockAPI = mock[SomeAPI]
    val ref = TestActorRef(new SomeActor(mockAPI))

    expecting {
      mockAPI.foo("Hi").once()
    }

    whenExecuting(mockAPI) {
      ref.tell("Hi",testActor)
    }
  }

  it("ok actor") {
    val ref = TestActorRef(new Actor {
      def receive = {
        case "Hi"  => sender ! "Hello"
      }
    })
    ref.tell("Hi",testActor)
    expectMsg("Hello")
  }
}

“problemExample”传递,但是下游“ok actor”由于某种原因失败,我真的不明白……有这个例外:

cannot reserve actor name '$$b': already terminated
java.lang.IllegalStateException: cannot reserve actor name '$$b': already terminated
at       akka.actor.dungeon.ChildrenContainer$TerminatedChildrenContainer$.reserve(ChildrenContainer.scala:86)
at akka.actor.dungeon.Children$class.reserveChild(Children.scala:78)
at akka.actor.ActorCell.reserveChild(ActorCell.scala:306)
at akka.testkit.TestActorRef.<init>(TestActorRef.scala:29)

所以,我可以通过检查afterEach处理程序中的记录器输出来看到捕获此类事物的方法.绝对可行,虽然在我实际期待异常的情况下有点复杂,而这正是我想要测试的.但有没有更直接的方法处理这个并使测试失败?

附录:我看过TestEventListener并怀疑那里可能会有什么帮助,但我看不到它.我能找到的唯一文件是用它来检查预期的异常,而不是意外的异常.

解决方法

在演员中思考还有另一种解决方案:故障传递给主管,因此这是捕捉它们并将它们输入测试程序的理想场所:

val failures = TestProbe()
val props = ... // description for the actor under test
val failureParent = system.actorOf(Props(new Actor {
  val child = context.actorOf(props,"child")
  override val supervisorStrategy = OneForOneStrategy() {
    case f => failures.ref ! f; Stop // or whichever directive is appropriate
  }
  def receive = {
    case msg => child forward msg
  }
}))

您可以通过发送到failureParent发送给被测试的演员,并且所有故障 – 预期或不发生 – 都会转到故障探测器进行检查.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读