如何在集群分片测试环境中模拟参与者?

时间:2020-05-24 19:30:19

标签: scala akka-cluster akka-persistence akka-testkit akka-typed

我已经成功地通过akka和scala为事件源行为设置了测试环境,并且可以通过这样做对独立的演员正确运行单元测试

class CQRSActorSpec
    extends ScalaTestWithActorTestKit(
      EventSourcedBehaviorTestKit.config.withFallback(CQRSActorSpec.config)
    )

然后创建我的测试包

private val myTestKit = EventSourcedBehaviorTestKit[Command, Event, State](system, MyActor)

并使用它发出命令

val result = myTestKit.runCommand[Response](StartJob(parameters, _))
result.reply shouldBe Done
result.event shouldBe Started(parameters)
result.state shouldBe ProcessingJob

现在,我要对一个在其生命周期中调用另一个actor的actor进行单元测试,这是因为我使用的是saga模式,所以我要测试的actor是该saga的主管,必须与所涉及的各方联系。

到目前为止,我已经做到了以下几点:

val mockParty = Behaviors.receiveMessage[Party.Command] { msg =>
  val reply = msg match {
    case _ => Done
  }
  msg.replyTo ! reply
  Behaviors.same
}

ClusterSharding(system).init(Entity(Party.Key) { _ => mockParty })

这在第一次测试中运行正常,但是随后当我不得不测试另一个(例如失败案例)时,第二个调用当然将无法工作,因为集群分片中已经注册了一个实体,并且我无法覆盖该行为。另外,无法重置集群分片。

有人对如何解决此问题有见解吗?还有其他我不知道的用于测试集群分片的实用程序吗?我发现文档有些缺乏。

1 个答案:

答案 0 :(得分:0)

问题的根源是在代码中使用ClusterSharding(system),这将创建真正的ClusterSharding对象,就像您说的那样,您无法控制测试。相反,您应该从外部传递ClusterSharding对象,以便可以对其进行存根/模拟实现。

这是我正在谈论的Java渲染概述:

让我们假设类型为EntityA的持久性行为者/事件的行为将创建并与类型为EntityB的另一个持久性行为者/事件的行为进行交互。

在您的应用程序代码中的某处,您将对ClusterSharding.init(..)进行EntityA调用:

ClusterSharding sharding = ClusterSharding.get(actorSystem); //the real stuff in the app
sharding.init(
      Entity.of(
        EntityA.ENTITY_TYPE_KEY,
        entityContext ->
          EntityA.create(
            entityContext.getEntityId(),
            sharding
          )
      )
    );

请注意sharding对象如何传递给create的{​​{1}}方法,并且是EntityA与之交互的ClusterSharding对象。

在单元测试中,将不会调用此代码,而是可以在初始化testKit时注入自己的EntityA实现:

ClusterSharding

因此,现在在您的//this is in test ClusterSharding sharding = new ClusterShardingStub(); //your stub/mock var esbtk = EventSourcedBehaviorTestKit.create( testKit.system(), EntityA.create("entityId", sharding)); 实现的逻辑中,您大概将调用EntityA来获取sharding.entityRefFor(...)的实例。您需要做的是对存根/模拟程序进行编程以返回EntityRef<EntityBProtocol>实例:

TestEntityRef.of(..)

现在TestProbe<EntityBProtocol> testProbe = TestProbe.create(testKit.system()); EntityRef<EntityBProtocol> ref = TestEntityRef.of(EntityB.ENTITY_TYPE_KEY, "entityId", testProbe.ref()); EntityA的任何交互都可以使用EntityB实例进行断言。