有没有办法在 Actor 的接收定义中获取 "stored" 值?

Is there a way to obtain the "stored" value within a receive definition of an Actor?

我希望能够针对“存储”到我的参与者的接收函数中的值进行断言。有没有办法用任何 Akka 测试库来做到这一点?

在下面的例子中,我想获得currentCount

import akka.actor.Actor

class CounterActor extends Actor {
  import CounterActor._
  
  override def receive: Receive = count(0) 

  def count(currentCount: Int): Receive = { 
    case Increment => context.become(count(currentCount + 1))
    case Decrement => context.become(count(currentCount - 1))
  }
}

object CounterActor {
  case object Increment
  case object Decrement
}

然后我想用测试来反对它 class:

val counterActorRef = TestActorRef(new CounterActor())

"A counter actor" should {
  "have a count of 3" in {
    counterActorRef ! CounterActor.Increment
    counterActorRef ! CounterActor.Increment
    counterActorRef ! CounterActor.Increment
    
    val counterValue = // obtain currentCount from counterActorRef
    assert(counterValue == 3)
  }
}

我试过使用 TestActorRef,但没有成功。我知道有一种方法可以通过添加消息案例来获得它来满足这一点,或者添加一些 Debug/Info 级别的日志消息并使用 EventFilter。有没有简单的方法可以通过我不知道的测试库来获取它?

我已经在 akka.testkit 个库中搜索了一段时间,但找不到我的解决方案。

感谢任何帮助,谢谢。

您想做什么 - ask 演员关于他的状态和 assert 它在测试中的状态。 第一步——读取值:

import akka.actor.Actor

class CounterActor extends Actor {
  import CounterActor._
  
  override def receive: Receive = count(0) 

  def count(currentCount: Int): Receive = { 
    case Increment => context.become(count(currentCount + 1))
    case Decrement => context.become(count(currentCount - 1))
    case Read => sender() ! 
  }
}

object CounterActor {
  case object Increment
  case object Decrement
  case object Read
  case class CurrentValue(currentCount: Int) //for type safety
}

第二步 - 在测试中断言:

val counterActorRef = TestActorRef(new CounterActor())

"A counter actor" should {
  "have a count of 3" in {
    counterActorRef ! CounterActor.Increment
    counterActorRef ! CounterActor.Increment
    counterActorRef ! CounterActor.Increment
    
    val counterValue = (counterActorRef ? Read).futureValue
    assert(counterValue == CurrentValue(3))
  }
}

演员模型有两个特点:

  • actor 状态的封装是彻底的并且(在 JVM 上,有效地(因为可能通过反射破坏封装))完成。

  • 观察到 actor 的状态仅在其行为(它如何响应消息,以及在 Akka 的情况下(它不是“actors all the way down”)的情况下才重要)是什么它执行的副作用)会因该状态而改变。

为了验证状态转换是否发生,您只能测试其行为是否符合预期。公开查询消息是一种方法;诸如点击日志条目流或(如果是事件源,则为持久性事件流)之类的东西是其他的。

也就是说,仅出于启用可测试性的目的公开查询消息通常不是可行的方法(它可能对操作调试有用)。理想的情况是测试参与者响应状态变化的“带内”行为(例如,“在发送 A 为真的消息后,对 B 为真的消息的响应显示 属性 C”)。如果状态改变没有以某种方式表现为行为改变,为什么状态改变会发生?

换句话说,将其他参与者视为黑盒服务通常很好。如果你正在测试 SO,你不可能验证“在 posting 一个问题之后,数据库中的这个字段被设置为这个值”(因为你作为用户无权访问数据库并且你不能提供一个你控制的模拟)。您可以验证的是“当我 post 一个问题时,我会得到一个问题 ID,当我请求该 ID 时,我会得到问题的内容”。