Command Handler reliant on another aggregate root for instantiation

Hi,

I am having difficulties testing my command handler as the aggregate root in test, relies on another aggregate root for instantiation. I’m sure im not the first problem to have this problem so I am probably missing something, my code is as follows:

`

public class DayTicketWater extends AbstractAnnotatedAggregateRoot {

public DayTicketWater(DayTicketWaterId id, String name) {
this.id = id;
apply(new DayTicketWaterBuilt(id, name));
}

public DayTicketSession scheduleSession(DayTicketSessionId sessionId, SessionPeriod period) {
return new DayTicketSession(sessionId, this.id, period, this.pegs);
}
}

public class DayTicketSession extends AbstractAnnotatedAggregateRoot {

@AggregateIdentifier
private DayTicketSessionId id;
private ArrayList availablePegs = new ArrayList<>();

@SuppressWarnings(“UnusedDeclaration”)
DayTicketSession() {}

public DayTicketSession(DayTicketSessionId id, DayTicketWaterId waterId, SessionPeriod period, ArrayList pegs) {
apply(new DayTicketSessionScheduled(id, waterId, period, pegs));
}
}

public class DayTicketSessionCommandHandler {

private Repository repository;
private Repository waterRepository;

@Autowired
public DayTicketSessionCommandHandler(Repository repository, Repository waterRepository) {
this.repository = repository;
this.waterRepository = waterRepository;
}

@CommandHandler
public void handle(ScheduleDayTicketSession command) {
DayTicketWater water = waterRepository.load(command.getWaterId());
DayTicketSession session = water.scheduleSession(command.getId(), command.getPeriod());

repository.add(session);
}
}

public class DayTicketSessionCommandHandlerTest {

private FixtureConfiguration fixture;
private FixtureConfiguration waterFixture;

@Before
public void setUp() {
fixture = Fixtures.newGivenWhenThenFixture(DayTicketSession.class);
waterFixture = Fixtures.newGivenWhenThenFixture(DayTicketWater.class);
DayTicketSessionCommandHandler commandHandler = new DayTicketSessionCommandHandler(fixture.getRepository(), waterFixture.getRepository());
fixture.registerAnnotatedCommandHandler(commandHandler);
}

@Test
public void it_should_schedule_session_with_pegged_water() {

DayTicketSessionId id = DayTicketSessionId.generate();
SessionPeriod sessionPeriod = new SessionPeriod(LocalDate.of(2010, 10, 1), LocalDate.of(2010, 10, 2));
DayTicketWaterId waterId = DayTicketWaterId.generate();
Peg peg = new Peg(“The Shallows”);

waterFixture.given(
new DayTicketWaterBuilt(waterId, “Fishery 1”),
new PegAddedToDayTicketWater(waterId, peg)
);

fixture.given()
.when(new ScheduleDayTicketSession(id, waterId, sessionPeriod))
.expectVoidReturnType()
.expectEvents(new DayTicketSessionScheduled(id, waterId, sessionPeriod, new ArrayList<>(Arrays.asList(peg))));
}
}

`

As you can see the DayTicketSession is instantiated by DayTicketWater when invoking the scheduleSession method. I obviously want to add tests for this, if you check my DayTicketSessionCommandHandlerTest, this is where the problem is. The error is as follows:

The aggregate loaded based on the generated events seems to be of another type than the original. Working type: <DayTicketWater> Event Sourced type: <DayTicketSession>

I think this may be a duplicate of https://groups.google.com/forum/#!msg/axonframework/4Fc26pCtpWI/8t01OfB1wnMJ, does the outcome of mocking still apply?

Hi Matt,

yes, I believe the outcome is still the same. Accessing an aggregate root from another is at least a design smell in cqrs. A single command should invoke a single aggregate. If it needs external data for anything, use a query model instead.

Cheers,

Allard

Thanks for the quick reply!

Using the DayTicketWater as a Factory class with the method of scheduleSession better suits the ubiquitious language. I have also seen this type of instantiating in other DDD / CQRS applications so i dont think its a design smell, see https://groups.google.com/forum/#!topic/dddcqrs/B6kxs7FK8_I

Hi Matt,

I wasn’t aware that one aggregate was the factory of the other. So it’s not really one aggregate that is accessing another, but one that uses its state to validate the creation of another. That is in fact a design that is considered quite the opposite of bad design.

I haven’t tried, but it might be possible to do this in the current Axon API. Just create an aggregate instance from another aggregate and have it apply events. You do need to add() that newly created instance to an appropriate repository.

In Axon 3, we will take this use case into account in the API design, to allow for a cleaner solution.

Cheers,

Allard

Hi Allard,

Yes this is what i have done (see code above). However its not working as expecting, maybe i’m doing something wrong?

Should i be using two fixtures side by side, the first fixture setting up the state of the factory aggregate, then the second fixture will create the new instance using the factory method?

Thanks

Hi Matt,

I am afraid the fixtures can’t cope with this situation. The fixtures are hard-wired to support only a single aggregate instance. You’d probably have to test the behavior without the fixtures, for this case.

Cheers,

Allard