0

By the definition of CQRS command can/should be validated and at the end even declined (if validation does not pass). As a part of my command validation I check if state transition is really needed. So let take a simple, dummy example: actor is in state A. A command is send to actor to transit to state B. The command gets validated and at the end event is generated StateBUpdated. Then the exact same command is send to transit to state B. Again command gets validated and during the validation it is decided that no event will be generated (since we are already in state B) and just respond back that command was processed and everything is ok. It is kind of idempotency thingy.

Nevertheless, I have hard time (unit) testing this. Usual unit test for persistent actor looks like sending a command to the actor and then restarting actor and check that state is persisted. I want to test if I send a command to the actor to check how many events were generated. How to do that?

Thanks

zmeda
  • 2,909
  • 9
  • 36
  • 56

2 Answers2

1

We faced this problem while developing our internal CQRS framework based on akka persistence. Our solution was to use Persistence Query(https://doc.akka.io/docs/akka/2.5/scala/persistence-query.html). In case you haven't used it, it is a query interface that journal plugins can optionally implement, and can be used as the read side in a CQRS system.

For your testing purposes, the method would be eventsByPersistenceId, which will give you an akka streams Source with all the events persisted by an actor. The source can be folded into a list of events like:

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();
}

Sorry if the above seems bloated, we use Java, so if you are used to Scala it is indeed ugly. Getting the readJournal is as easy as:

ReadJournal readJournal = PersistenceQuery.lookup().get(actorSystem)
    .getReadJournalFor(InMemoryReadJournal.class, InMemoryReadJournal.Identifier())

You can see that we use the akka.persistence.inmemory plugin since it is the best for testing, but any plugin which implements the Persistence Query API would work.

We actually made a BDD-like test API inside our framework, so a typical test looks like this:

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();

As you see, we also handle the case of setting up previous events in the given clause as well a potentially dealing with multiple persistenceIds(we use ClusterSharding).

Pedro
  • 1,032
  • 6
  • 12
0

From you description it sounds like you need either to mock your persistence, or at lest be able to access it's state easily. I was able to find two projects that will do that:

akka-persistence-mock which is designed for use in testing, but not actively developed.

akka-persistence-inmemory

which is very useful when testing persistent actors, persistent FSM and akka cluster.

I would recommend the latter, since it provides the possibility of retrieving all messages from the journal.

mpm
  • 3,534
  • 23
  • 33