In my previous blog post about Axon, I showed how to create a simple application that uses event sourcing. In the end, you could call a REST API and test the application manually. I completely left out automated testing, even though I’m a big fan of Test-Driven Development. This was on purpose because I wanted to concentrate on the absolute basics. This time I wanted to show how to test applications with Axon.
I will write all the tests with JUnit 5. To support it you have to add JUnit 5 to the pom.xml and exclude the old JUnit:
There are a few changes between JUnit4 and JUnit 5. If you want to know more about it, you can read the official user guide.
Testing the aggregate
The BankAccount from my previous post is a simple aggregate which contains methods to react to events. You can use these methods to apply some events and in the end, verify the state of the aggregate, in this case, the account balance:
This test modifies the state of the aggregate without any additional framework (except Junit). It does not even call Axon specific code. This way of testing works as long as you don’t want to test commands. If you look into the implementation of e.g. BankAccount.on(DepositMoneyCommand), you will see that it calls
AggregateLifecycle.apply(newMoneyDepositedEvent(id,amount)); to publish an event. This will fail because Axon isn’t aware of the aggregate and cannot retrieve its lifecycle.
Axon Test Fixture
To test the command handling components Axon provides a test fixture. You can add it to your pom and start testing:
The test fixture provides an API where you define a test scenario with:
the events that already happened
the command you want to execute
the events or exception you expect
Before you write the first test you need to instantiate the test fixture with the aggregate class that you want to test:
As you can see, the test has no prerequisites, it’s like working on an empty database. when(…) sends a command, in this case, to create a new bank account. Then you verify that everything is successful and the expected AccountCreatedEvent is emitted.
With previous events
If the test requires a certain state of an aggregate, i. e. the aggregate has already processed some command (which lead to events), you define one or more events as given. The state of the aggregate is then built upon these events.
In this case, the Axon Framework prevents an aggregate from being created twice. The same works if you try to send a command for an aggregate that does not exist. As a result, Axon will throw an AggregateNotFoundException:
With little effort, and completely without Axon dependencies, it is possible to test the event processing of a single aggregate. If you want to go further and test commands, you can use the Axon Test Fixture. It provides a fluent API, which allows writing tests that are easy to read. You can set up an aggregate in the wanted state, apply new commands and verify the result. With this knowledge, you should be able to effectively test your event sourcing application and prevent bugs.