我已经成功地通过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 })
这在第一次测试中运行正常,但是随后当我不得不测试另一个(例如失败案例)时,第二个调用当然将无法工作,因为集群分片中已经注册了一个实体,并且我无法覆盖该行为。另外,无法重置集群分片。
有人对如何解决此问题有见解吗?还有其他我不知道的用于测试集群分片的实用程序吗?我发现文档有些缺乏。
答案 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
实例进行断言。