1

Недавно я изучаю CQRS, поэтому начал проект с аксоном-каркасом (инфраструктура java CRQS).Как объединить тестовые модели домена с аксоном-каркасом

Согласно быстрому старту, я получил это ниже:

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 
    } 
} 

тест-код сводит меня написано модель предметной области и код интеграции с аксоном-остами, но она не распространяется на то, что побочном эффекте событие сделало , Где я их тестировал? например при вступлении в силу статус кредитной записи должен быть эффективным. Должен ли я создать экземпляр CreditEntry в других методах тестирования и теста, вызвав конкретный метод (... Event event)?

И еще один вопрос: где я должен поставить логику проверки бизнеса? В методе обработчика команд? Предполагая, что CreditEntry не может быть снова эффективен, поскольку он уже эффективен.

@CommandHandler 
public void markCompleted(MakeCreditEntryEffectiveCommand command) { 
    if (is(NEW)) { 
     apply(new CreditEntryMadeEffectiveEvent(
      command.getEntryId(), command.getStart(), command.getEnd())); 
    } else { 
     throw new IllegalStateException(.......); 
    } 
} 

Любая идея ценится, спасибо.

+0

Вы не используете агрегаты? – Mzzl

ответ

5

На ваш первый вопрос: Вы имеете в виду под действием побочного эффекта внутреннего состояния вашего агрегатного объекта? Тест «Принятый после того времени» рассматривает агрегат как своего рода черный ящик. Так что действительно нет необходимости проверять внутреннее состояние. Важно только, чтобы были применены правильные события.

Так, например, вы можете даже заполнить агрегаты без каких-либо полей (ожидать идентификатор), поскольку ваша логика принятия решений не зависит от какого-либо внутреннего состояния. Как правило, я сохраняю только данные, переносимые в событии в агрегированном объекте, если мне это нужно позже, чтобы решить, какие события применять или изменить данные, применяемые в событии.

Если вы помните об этом, вам не нужно проверять внутреннее состояние. Вы просто настраиваете агрегат с определенными событиями в данном разделе (создаете некоторое состояние), а затем применяете команду. Если появятся правильные события ... все готово.

На ваш второй вопрос: Подтверждение бизнеса должно выполняться в обработчике команд. Поэтому все должно быть проверено до того, как вызывается метод apply. Одна из причин этого. Представьте себе систему, в которой логика проверки изменяется в течение срока службы, но вам приходится иметь дело со старыми данными, которые были введены при вводе системы. Если проверка будет выполняться в обработчике событий, а проверка не будет такой же, как когда событие было впервые введено, загрузка агрегата из событий может завершиться неудачно, поскольку «старые» данные не соответствуют текущей логике проверки.

+0

Спасибо за ответ. Мне потребовалось некоторое время, чтобы понять, что событие является ключом к этой архитектуре :) – Hippoom