Is there a way to test events from the test fixture directly without using expectEvents?

Im trying to test an Aggregate and would like to assert the events outside of the fixture and perhaps even use Hamcrest to evaluate?

An example of using timestamps

        fixture.given()
           .when(new UserCreateCommand("1","[email protected]"))
           .expectEvents(new UserCreatedEvent("1","[email protected]");

The fixture allows me to easily test equality, e.g. the command produces exactly this event, its not so easy if I wanted to say introduce a Timestamp of when the event was created for example

        fixture.given()
           .when(new UserCreateCommand("1","[email protected]"))
           .expectEvents(new UserCreatedEvent("1","[email protected]", LocalDateTime.now());

This expectation will never work as the LocalDateTime.now() will never be precisely equal to the timestamp generated in the aggregate.

I could simply include the Timestamp in the command payload, but feel a preference to handle inside the Aggregate to ensure a consistent way of generating this timestamps.

Is there a way to retrieve the Event out of the fixture to assert independently of the fixture e.g.

   UserCreatedEvent uce = fixture.given()
           .when(new UserCreateCommand("1","[email protected]"))
           .extractEvent(UserCreatedEvent.class)

This would then allow me to use other assertion libraries also like hamcrest for example:

e.g.

   assertThat(uce.getCreatedAt(), is(greaterThanOrEqualto(LocalDateTime.now().minusSeconds(1);


Solution 1:

Reasonable question @vcetinick!

You should actually be able to use matchers with Axon's Aggregate Test Fixtures really. The result validation part of the AggregateTestFixture provides the expectEventsMatching(Matcher<? extends List<? super EventMessage<?>>> matcher) method. You can find the code for this here by the way.

On top of this Axon Framework provides a set of reasonable matchers you can use for messages in general, grouped under the utility class Matchers (which you can find here).

With all this in place, you should be able to do something like this:

@Test
void sampleTest() {
    FixtureConfiguration<SampleAggregate> fixture = 
        new AggregateTestFixture<>(SampleAggregate.class);
    fixture.givenNoPriorActivity()
           .when(new UserCreateCommand("1","[email protected]"))
           .expectEventsMatching(
                   Matchers.exactSequenceOf(
                           Matchers.messageWithPayload(
                                   Matchers.matches(payload -> {
                                       // Your UserCreatedEvent validation 
                                       //  disregarding the time stamp here
                                   })
                           )
                   )
           );
}

You can essentially pair any number of Matchers methods in their if you desire.

Hoping this answers your question @vcetinick!