如何测试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
相关产品推荐
相关产品推荐

