通过CQRS命令的定义可以/应该验证并且最后甚至拒绝(如果验证没有通过)。作为我的命令验证的一部分,我检查是否真的需要状态转换。因此,让我们举一个简单的虚拟示例:actor处于状态A.命令被发送到actor以转移到状态B.命令被验证并且在结束时生成事件StateBUpdated
。然后发送完全相同的命令以转移到状态B.再次命令得到验证,并且在验证期间确定不会生成任何事件(因为我们已经处于状态B)并且只是响应该命令被处理并且一切都是好。这是一种幂等的东西。
然而,我很难(单位)测试这个。持久性actor的常用单元测试看起来像向actor发送命令然后重新启动actor并检查状态是否持久化。我想测试是否向actor发送命令以检查生成了多少事件。怎么做?
由于
答案 0 :(得分:1)
我们在开发基于akka持久性的内部CQRS框架时遇到了这个问题。我们的解决方案是使用持久性查询(https://doc.akka.io/docs/akka/2.5/scala/persistence-query.html)。如果您还没有使用它,它是日志插件可以选择实现的查询接口,并且可以用作CQRS系统中的读取端。
为了您的测试目的,该方法将是eventsByPersistenceId,它将为您提供akka流源,其中包含actor所持有的所有事件。源可以折叠成一系列事件,如:
public CompletableFuture<List<Message<?>>> getEventsForIdAsync(String id, FiniteDuration readTimeout) {
return ((EventsByPersistenceIdQuery)readJournal).eventsByPersistenceId(id, 0L, Long.MAX_VALUE)
.takeWithin(readTimeout)
.map(eventEnvelope -> (Message<?>)eventEnvelope.event())
.<List<Message<?>>>runFold(
new ArrayList<Message<?>>(),
(list, event) -> {
list.add(event);
return list;
}, materializer)
.toCompletableFuture();
}
很抱歉,如果上面看起来很臃肿,我们使用Java,所以如果你习惯了Scala,那确实很难看。获取readJournal非常简单:
ReadJournal readJournal = PersistenceQuery.lookup().get(actorSystem)
.getReadJournalFor(InMemoryReadJournal.class, InMemoryReadJournal.Identifier())
您可以看到我们使用akka.persistence.inmemory插件,因为它最适合测试,但任何实现持久性查询API的插件都可以使用。
我们实际上在我们的框架中制作了类似BDD的测试API,所以典型的测试看起来像这样:
fixture
.given("ID1", event(new AccountCreated("ID1", "John Smith")))
.when(command(new AddAmount("ID1", 2.0)))
.then("ID1", eventApplied(new AmountAdded("ID1", 2.0)))
.test();
如您所见,我们还处理在给定子句中设置先前事件以及可能处理多个persistenceIds的情况(我们使用ClusterSharding)。
答案 1 :(得分:0)
从你的描述中听起来你需要模仿你的持久性,或者至少能够轻松地访问它的状态。我能够找到两个可以做到这一点的项目:
akka-persistence-mock设计用于测试但未积极开发。
在测试持久性actor,持久性FSM和akka集群时非常有用。
我会推荐后者,因为它提供了从期刊中检索所有邮件的可能性。