Testing command, event and aggregate (de)serialization
See original GitHub issueGiven the discussion here I was asked to create an issue here in order to discuss testing (de)serialization of commands, events and snapshots.
I’ve created a small sample project in which I show how we currently at Orangebeard test (de)serialization of events and how we test our upcasters: https://github.com/maartenjanvangool/axon-event-testing
Testing the deserialization can be done like this (this is kotlin):
// should be the serializer used in production
private val serializer = XStreamSerializer.builder().xStream(XStream()).build()
@Test
fun can_serialize_and_deserialize() {
val serializedObject = serializer.serialize(event, String::class.java)
val result = serializer.deserialize<String, FlightCreatedEvent>(serializedObject)
assertXMLEquals(serializedObject.data, xml)
assertThat(event).isEqualTo(result)
}
private val event: FlightCreatedEvent = FlightCreatedEvent(
1L,
LocalDateTime.parse("2019-10-08T12:42:23.329")
)
//language=xml
private val xml = """
<io.orangebeard.events.FlightCreatedEvent>
<flightId>1</flightId>
<departureTime>2019-10-08T12:42:23.329</departureTime>
</io.orangebeard.events.FlightCreatedEvent>"""
And testing the working of an upcaster like this:
// should be the serializer used in production
private val serializer = XStreamSerializer.builder().xStream(XStream()).build()
private val v1Upcaster = FlightDelayedEventV1Upcaster()
@Test
fun can_upcast() {
val event = InitialEventRepresentation(
GenericDomainEventEntry(
"io.orangebeard.events.FlightDelayedEvent",
"12045560",
1L,
"a904422b-6ae0-4123-a08a-e1e0cfd0f7bd",
"2019-10-17T11:58:20.688Z",
"io.orangebeard.events.FlightDelayedEvent",
"1",
xmlV1,
""), serializer)
assertThat(v1Upcaster.canUpcast(event)).isTrue()
val result = v1Upcaster.doUpcast(event)
assertThat(result.data.type.revision).isEqualTo("2")
assertXMLEquals(xmlV2, (result.data.data as AbstractDocument).asXML())
}
//language=xml
private val xmlV1 = """
<io.orangebeard.events.FlightCreatedEvent>
<flightId>1</flightId>
<departureTime>2019-10-08T12:42:23.329</departureTime>
<reason>SECURITY_PROBLEM</reason>
</io.orangebeard.events.FlightCreatedEvent>"""
//language=xml
private val xmlV2 = """
<io.orangebeard.events.FlightCreatedEvent>
<flightId>1</flightId>
<departureTime>2019-10-08T12:42:23.329</departureTime>
<reason>SECURITY_ISSUE</reason>
</io.orangebeard.events.FlightCreatedEvent>"""
The issue I encountered was that there does not seem a good way to test deseralization of aggregate snapshots. Since events and commands are simple pojo’s, one can just instantiate these and test the deserialization. This is not possible with aggregates. And changing the aggregate while not changing the snapshot revision number can have some dire consequences.
So I essentially propose an extension to the test fixture where I can pass along the serializer used, as well as snapshots in order tot test the interaction between snapshot and aggregate (changes), which may look something like this:
@BeforeEach
public void setUp() {
// pass serializer as an argument (or as a bean)
fixture = new AggregateTestFixture<>(FlightAggregate.class, serializer);
}
@Test
public void the_aggregate_snapshot_serializes_correctly() {
fixture.givenNoPriorActivity()
.when(new FlightCreatedEvent(1L, now))
.expectSnapshotToMatch(snapshotXML);
}
@Test
public void the_aggregate_snapshot_deserializes_correctly() {
fixture.givenSnapshot(snapshot)
.when(new FlightCreatedEvent(1L, now))
...
}
What do you guys think?
Issue Analytics
- State:
- Created 2 years ago
- Reactions:2
- Comments:5 (4 by maintainers)
I wouldn’t indeed assume they would, @TomDeBacker. The times I did help teams integrate with Axon Framework, we always reached a point where we introduced a test suite in the staging environment that validated all events and snapshots with the Serializer and Upcasters in place. However, this was always purpose-built, whereas a form of support from within the framework does sound like a friendly gesture to me.
So, your team is right! But that does not necessarily mitigate this issue at this stage I believe. 😃
I’m looking through some of the issues to provide some feedback. This is one of the things we do by default in our team. As stated, it is probably not a big priority but seems to be something that could reduce developer overhead, even if minimal. You will have to take the specific event serializer used into account in any case. +1 from me