You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何测试Akka中EventSourcedBehavior的停止行为?

问题

我有一个EventSourcedBehavior,收到特定消息后会生成最后一个事件并自行停止,业务逻辑本身没问题,但测试时出现了DeadLetter死信消息——原因是EventSourcedBehaviorTestKit调用runCommand后会立即发送一条GetState消息,而此时行为已经停止,无法响应。

我查了EventSourcedBehaviorTestKit的API文档,没找到合适的方法实现测试目标。

以下是复现问题的测试代码:

"test behavior stop" in {
    sealed trait Command
    case object Hi extends Command

    sealed trait Event

    sealed trait State
    case object Empty extends State

    val behavior = EventSourcedBehavior[Command, Event, State](
        PersistenceId.ofUniqueId("1"), 
        Empty, 
        (_,_) => Effect.none.thenStop(), 
        (_,_) => Empty)

    val kit = EventSourcedBehaviorTestKit[Command, Event, State](system, behavior)
    kit.runCommand(Hi)              
} 

对应的错误日志:

[2022-10-31 19:30:30,059] [INFO] [akka.actor.LocalActorRef] [SomeSpec-akka.actor.default-dispatcher-3] [akka://SomeSpec/system/test/$a] - Message [akka.persistence.typed.internal.EventSourcedBehaviorImpl$GetState] to Actor[akka://SomeSpec/system/test/$a#-553414380] was not delivered. [1] dead letters encountered. If this is not an expected behavior then Actor[akka://SomeSpec/system/test/$a#-553414380] 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'.

测试失败信息:

- must test behavior stop *** FAILED ***
[info]   java.lang.AssertionError: Timeout (3 seconds) during receiveMessage while waiting for message.
[...]

build.sbt配置:

build.sbt
---------
...

lazy val akkaVersion = 2.6.19

"com.typesafe.akka" %% "akka-actor-testkit-typed" % akkaVersion     % Test,
"com.typesafe.akka" %% "akka-persistence-testkit" % akkaVersion     % Test,
"org.scalatest"     %% "scalatest"                % "3.1.4"         % Test
...

请问如何设置测试,才能执行该命令并验证行为已停止?

解决方案

EventSourcedBehaviorTestKit的runCommand设计逻辑是发送命令后尝试获取状态,而你的行为处理完命令直接停止,导致后续GetState消息变成死信,测试超时失败。要测试这种停止逻辑,推荐换用ActorTestKit直接创建行为实例,配合TestProbe监听终止信号:

测试代码修改示例

"test behavior stop correctly" in {
  sealed trait Command
  case object Hi extends Command

  sealed trait Event
  sealed trait State
  case object Empty extends State

  val behavior = EventSourcedBehavior[Command, Event, State](
    PersistenceId.ofUniqueId("1"),
    Empty,
    (_, _) => Effect.none.thenStop(),
    (_, _) => Empty
  )

  val testKit = ActorTestKit()
  // 创建监听终止事件的探针
  val terminationProbe = testKit.createTestProbe[Terminated]()
  // 创建行为的ActorRef并订阅其终止事件
  val actorRef = testKit.spawn(behavior)
  terminationProbe.watch(actorRef)

  // 发送目标命令
  actorRef ! Hi

  // 验证Actor是否正常终止
  terminationProbe.expectMessageType[Terminated].ref shouldBe actorRef
}

备选方案(不推荐)

如果一定要用EventSourcedBehaviorTestKit,可以通过测试配置关闭死信日志,同时放弃runCommand的状态获取逻辑,但这种方式不如上面的方案直接清晰:
在测试配置文件中添加:

akka.log-dead-letters = off
akka.log-dead-letters-during-shutdown = off

内容的提问来源于stack exchange,提问作者null

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 00:31:01