I'm learning CQRS recently, so I started a sample project with axon-framework(A java CRQS framework).
According to the quick start, I got this below:
public class CreditEntryUnitTests {
private FixtureConfiguration fixture;
@Before
public void setUp() throws Exception {
fixture = Fixtures.newGivenWhenThenFixture(CreditEntry.class);
}
@Test
public void creditEntryCreated() throws Throwable {
final Long entryId = 1L;
final int amount = 100;
fixture.given().when(new CreateCreditEntryCommand(entryId, amount))
.expectEvents(new CreditEntryCreatedEvent(entryId, amount));
}
@Test
public void creditEntryMadeEffective() throws Throwable {
final Long entryId = 1L;
final int amount = 100;
final Date start = nov(2011, 12);
final Date end = nov(2012, 12);// a year effective period
fixture.given(new CreditEntryCreatedEvent(entryId, amount))
.when(new MakeCreditEntryEffectiveCommand(entryId, start, end))
.expectEvents(new CreditEntryMadeEffectiveEvent(entryId, start, end));
}
//omitted support methods
}
public class CreditEntry extends AbstractAnnotatedAggregateRoot {
@AggregateIdentifier
private Long id;
private int amount;
private Date effectiveDateRangeStart;
private Date effectiveDateRangeEnd;
private Status status;
@CommandHandler
public CreditEntry(CreateCreditEntryCommand command) {
apply(new CreditEntryCreatedEvent(
command.getEntryId(), command.getAmount()));
}
@EventHandler
public void on(CreditEntryCreatedEvent event) {
this.id = event.getEntryId();
this.amount = event.getAmount();
this.status = Status.NEW;
}
@CommandHandler
public void markCompleted(MakeCreditEntryEffectiveCommand command) {
apply(new CreditEntryMadeEffectiveEvent(
command.getEntryId(), command.getStart(), command.getEnd()));
}
@EventHandler
public void on(CreditEntryMadeEffectiveEvent event) {
this.effectiveDateRangeStart = event.getStart();
this.effectiveDateRangeEnd = event.getEnd();
this.status = Status.EFFECTIVE;
}
public CreditEntry() {}
public enum Status {
NEW, EFFECTIVE, EXPIRED
}
}
The test code drives me written the domain model and integration code with axon-framework but it doesn't cover what side effect the event made. Where did I test them? e.g. when made effective the credit entry's status should be effective. Should I create a CreditEntry instance in other test methods and test by calling specific on(...Event event) method?
And one more question is: where should I put business validation logic? In command handler method? Assuming if the CreditEntry can not be made effective again given it is effective already.
@CommandHandler
public void markCompleted(MakeCreditEntryEffectiveCommand command) {
if (is(NEW)) {
apply(new CreditEntryMadeEffectiveEvent(
command.getEntryId(), command.getStart(), command.getEnd()));
} else {
throw new IllegalStateException(.......);
}
}
Any idea is appreciate, thank you.