Testing a pojo EventHandler between bounded contexts of executing commands on different ARs in Eventhandlers

Any guidance best practice for this…followed the cross AR communication guidelines from previous post and need to test, but some best practice to leverage Axon would be great.

The challenge is that these event handlers invoke commands via bus on different ARs and different ARs generate different events, so testing given when then on multiple ARs is the pattern in question.

Cheers

Hi,

what you’d need to test is 3 things:

  • AR1: does it provide the right events for the right past event and command? Use the Axon fixture for this.
  • AR2: same as AR1, but of course a different fixture
  • Saga: make sure the right commands are sent based on incoming events. Unfortunately, there is no Axon fixture, yet. A colleague of mine is doing some design work on a fixture for this. The easiest is probably to wire a mini-context with CommandBus, EventBus and EventListener/Saga.

Cheers,

Allard

Got 1 & 2… for 3 here is what I have so far

@Autowired

private EventBus eventBus;

@Autowired

private SagaRepository repository;

@Autowired

private PlatformTransactionManager transactionManager;

@Autowired

private SimpleCommandBus commandBus;

private EventListener listener;

@Test

public void testInvokeSaga() throws Exception {

assertNotNull(commandBus);

SomeEventHandlerSaga testSubject = new SomeEventHandlerSaga();

eventBus.publish(new SomeDomainEventHandledBySaga(SomeEventData data));

Now the assumption above is that Saga will automatically intercept via the spring config wiring, however how to subcribe/intercept and verify that a command with the appropriate command data got fired is in question? any tips…

Thanks…

There are 3 options:

I usually use Mockito for that kind of stuff. You can easily create a mock command bus that “records” all the activity on it. After sending the events, you can verify that the expected activity on the mock has taken place. You can even configure to invoke the callback parameter (using Mockito’s Answer mechanism) when a certain command is sent.Check out www.mockito.org for more info. Alternatively, you can achieve similar results with JMock or EasyMock. Mockito is my personal favorite, though.

Alternatively, you can create a stub implementation of the command bus that doesn’t process commands, but just stores incoming commands in a list. It should then expose that list to allow your test to validate it.

The third option is to wire a “real” command bus, and register command handlers in your test. That command handler would then do some assertions/verifications to make sure the command is correct. Don’t forget to failyour test if the handler isn’t invoked at all.

Cheers,

Allard

Thanks…

Having a challenge with mockito and some sample code resurrecting saga lifecycle.below seems more like infrastructure test to get a saga going vs Saga functionality test…cannot get same instances injected by spring and autowired in the unit test to be same hence get zero invocations and cannot verify…also question is where to do a setCommandBus on saga in the below lifecycle as it may not be possible…any ideas

@Mock CommandBus commandBus;

public test() {

final String randomAssociationValue = UUID.randomUUID().toString();

EventListener listener = mock(EventListener.class);

eventBus.subscribe(listener);

MyEventHandlerSaga saga = new TransactionTemplate(transactionManager)

.execute(new TransactionCallback() {

@Override

public MyEventHandlerSaga doInTransaction(TransactionStatus status) {

eventBus.publish(new StartingEvent(this, randomAssociationValue));

Set actualResult =

repository.find(MyEventHandlerSaga.class,

TestUtils.setOf(new AssociationValue(“association”,

randomAssociationValue)));

assertEquals(1, actualResult.size());

return actualResult.iterator().next();

}

});

ArgumentCaptor argument = ArgumentCaptor.forClass(MyCommand.class);

verify(commandBus).dispatch(argument.capture());//This commandBus is not the same as the one in the Saga and injected via spring hence get zero invocations…Can this Mock commandBus be injected in the above code by setCommandBus method on a Saga…cannot see where to to a setCommandBus on the Saga above…based on the lifecycle and state of the sage in the event publishing lifecycle.

assertEquals(randomAssociationValue, argument.getValue().getId());

}

Any other ideas…any very simple saga test example or insight which intercepts events and generates a command would be very valuable.

Thanks…

Hi,

it’s unclear to me what you’re exactly trying to test. I suppose that you want to verify whether your Saga is dealing with the incoming events in a correct way, right?

This is how I test the saga functinonally, without any infrastructure:

@Before
public void setUp() {
testSubject = new TournamentSaga();
mockCommandBus = Mockito.mock(CommandBus.class);
testSubject.setCommandBus(mockCommandBus);
}

@Test
public void testGamesStartedOnRoundStart() {
testSubject.handleRoundStarted(/create some round started event [1]/);

Mockito.verify(mockCommandBus).dispatch(commandWithSeating(“1”, “2”, “3”, “4”));
Mockito.verify(mockCommandBus).dispatch(commandWithSeating(“5”, “6”, “7”, “8”));
Mockito.verify(mockCommandBus).dispatch(commandWithSeating(“B”, “9”, “C”, “A”));
Mockito.verifyNoMoreInteractions(mockCommandBus);
}

At [1], not that I use a trick to set the AggregateIdentifier. In our project, we’ve created a Utils class for that. The fixture we’re working on will include this feature (probably implemented a bit better, though).
Here is the relevant code:

public static T forAggregate(String aggregateIdentifier, T domainEvent) {
T spy = Mockito.spy(domainEvent);
Mockito.when(spy.getAggregateIdentifier()).thenReturn(new StringAggregateIdentifier(aggregateIdentifier));
return spy;
}

Note that I don’t use to much infrastructure. That’s the whole idea of the annotation support: you can test your own logic without too much Axon infrastructure. Since your Saga also extends AbstractAnnotatedSaga, you can also invoke the handle(Event) method instead.

When using Mockito in combination with a Spring Application Context, I create a MockitoMockFactoryBean (which implements FactoryBean) to create mocks. You can then insert that bean into your test and do the necessary verifications on it.

Cheers,

Allard

Thanks…You right…this does clarify and simplify the testing context and exactly what I was hoping for and very helpful to functional test without any infrastructure, which was the intent…