The simplesource-command-testutils
module includes utility classes to help test your implementation.
AggregateTestDriver
implements the CommandAPI
interface. It uses the Kafka Streams
TopologyTestDriver
test tool to run the same topology used by the Simple Sourcing production code in your tests, mocking out Kafka, the Schema Registry and the communication between the command API and the Simple Sourcing instances.
AggregateTestHelper
provides a DSL built on top of AggregateTestDriver
for chaining together
publication of commands and making assertions about the inner state of the event sourcing library
after each command.
It also provides a simple mechanism to validate the correct event and aggregate state changes
occur as a result of each command.
An example is given below. We insert a new user then update their name. In each case we provide the expected events and projection state.
The second command will automatically get sent with the same key and sequence number of the last event from the previous command.
testHelper.publishCommand(
id,
Sequence.first(),
new UserCommand(new InsertUser(firstName, lastName)))
.expecting(
NonEmptyList.of(new UserEvent(new UserInserted(firstName, lastName))),
Optional.of(new User(id, firstName, lastName, null))
)
.thenPublish(
new UserCommand(new UpdateName(updatedFirstName, updatedLastName)))
.expecting(
NonEmptyList.of(
new UserEvent(new FirstNameUpdated(updatedFirstName)),
new UserEvent(new LastNameUpdated(updatedLastName))),
Optional.of(new User(id, updatedFirstName, updatedLastName, null))
)
There is also a variation of the thenPublish
method where you provide a function
that takes the last projection value and sequence and produces a new command with your own provided sequence id.
This is useful when you’re testing error scenarios. Below we’re creating a new user then we’re sending an update command
with an invalid sequence id.
We indicate we expect an error providing the expected failure reason.
testHelper.publishCommand(
id,
Sequence.first(),
new UserCommand(new InsertUser(firstName, lastName)))
.expecting(
NonEmptyList.of(new UserEvent(new UserInserted(firstName, lastName))),
Optional.of(new User(id, firstName, lastName, null))
)
.thenPublish(update ->
new ValueWithSequence<>(new UserCommand(new UpdateName(updatedFirstName, updatedLastName)), Sequence.first()))
.expectingFailure(NonEmptyList.of(InvalidReadSequence))