Everything works well. However, I’ve come across a situation where when we come to write integration tests the serialiser fails. In my particular case it is Jackson: it says cannot construct instance.
My question is: is there a way to pass a serializer to the fixture and have it attempt to serialize/deserialize each command and event it goes through?
I know the test fixture already does a lot and so adding this an option doesn’t seem too far fetched.
This way this type of bug can be found much quicker…
Having to write an integration test is quite long in comparison to having the fixture do it.
If the feature does not exist… do you think its worth having? If so I can open an issue on the Github page to track it.
On further reflection… I think it is probably not a good idea to have the test fixture perform this functionality.
Instead I am leaning towards having a separate test class for the command/query API types which just runs the test(s) (serialize/deserialize) on a random instance of each command/event/query…
I’ll update this thread with any generic code once I’ve written it for future reference…
i wrote some tests inside AxonFramework some time ago for a pull request that had to do with serialization. Maybe you could use this as a starting point, even tough it was made to test serialization parametrized for multiple serializers:
A question: in the test serializer the serialize method is defined as:
protected String serialize(Object object) {
return new String(getSerializer().serialize(object, byte[].class).getData());
}
What is the reason to serializing to byte[].class by default? I was thinking of testing if we could serialize to String - but does byte[].class make more sense? If so do you know why?
The build in Java Serialization produces binary data which is treated best with byte arrays. As far as I can remember, byte arrays are also involved when working with JSONB PostgreSQL database column type. If you don’t use any of these, Strings should be fine, I guess.
I’ll give a minimum reproducible example (in semi-pseudo semi-real code) below for future reference as well.
N.B. this requires the easy random library as a dependency and if you are using Java records you will currently need to initialise your EasyRandom() instance with a workaround described here (this is not done in the example below). Once Java records become standard a newer version of easy random will support it out of the box (and you can define your API commands/events using records rather than relying on lombok annotations).
So given the following API:
class SomeAggregateCommandAPI {
@Value
public static class CreationCommand {
@TargerAggregateIdentifier UUID id;
String a;
}
@Value
public static class AggregateCreatedEvent {
UUID id;
String a;
}
/......
}
Suppose we want to test each of the commands/events are serializable/deserializable we can create our test class which extends the abstract class defined in the gist:
class SomeAggregateCommandAPISerializationTest extends AbstractAPISerializationTest {
@Override
public Serializer getSerializer() {
// Grab the serializer we use in our actual app.
return new SerializerConfig().messageSerializer();
}
/**
* Pass all the types we want to test the Serializer with.
*/
@Override
public List<Class<?>> getTypes() {
var classes = Arrays.asList(SomeAggregateCommandAPI.class.getClasses());
return new ArrayList<>(classes);
}
}
This will end up running the following test (see the gist above for full code):
@ParameterizedTest
@MethodSource("provideTypes")
void serializeDeserialize(Class<?> type) {
// Given: a random instance of the type and the serializer.
var instance = easyRandom.nextObject(type);
Serializer serializer = getSerializer();
// When: We attempt to serialize and deserialize it.
assertThatCode(() -> {
var serializedObject = serializer.serialize(instance, String.class);
serializer.deserialize(serializedObject);
})
// Then: it does not throw...
.doesNotThrowAnyException();
}
Hope this comes in handy for anyone who wants to be able to test serialization/deserialization of their API objects.