1

我正在为基于参与者的应用程序编写测试用例。其中一个组件可以大致定义如下:

class MyActor(a: ActorRef, b: ActorRef) extends Actor {
    override def receive: Receive = {
        case _ => 
            a ! "Got message!"
            b ! "Hello!"
    }
}

现在,写一个我正在使用的测试用例akka-testkitand TestProbe。测试用例的一个重要部分如下所示:

val a = TestProbe()
val b = TestProbe()
val c = system.actorOf(Props(new MyActor(a.testActor, b.testActor)))

c ! "Message!"
a.expectMsg("Got message!")

现在的问题是测试用例通过了,即使发送到的消息b不是预期的,因此也没有经过验证。

我知道我可以b.expectNoMsg()在测试用例的开头调用它来解决这个特定问题,但不知何故我相信这不是一个真正可扩展的方法(我必须在所有预期的调用之后每次都添加它,这相当麻烦)。

所以我的问题是:是否可以选择akka-testkit在严格模式下运行,以便每条消息都必须以某种方式预期?首选方法是 via或配置TestKit,但任何不需要修改每个测试用例的解决方案都可以(因此在每次通信结束时调用不是解决方案)ActorSystemTestProbeexpectNoMsg()

4

1 回答 1

2

对于使测试失败的东西,它必须抛出执行测试的某种线程的断言错误,但是由于探针是异步的,因此您放入的任何故障检测都将发生在不同的线程上,因此需要从测试中调用方法的地方(就像expectNoMsg())。

话虽如此,您仍然可以抽象出该概念,例如挂钩到您的测试工具包中。

一种可能的方法是使用高阶函数:

def failOnUnexpectedMessage[T](test: ActorRef => T): T = {
  val probe = TestProbe()
  val result = test(probe.ref)
  probe.expectNoMsg()
  result
}

然后你可以在你的测试中使用它(Scalatest word spec style here):

"My actor" should {
  "something something" in failOnUnexpectedMessage { ref => 
    val actor = ...construct and pass it ref as b...
    ...rest of the test...
  }
}
于 2017-04-03T13:59:17.960 回答