如何测试依赖于时间的聚合?

How can I test an Aggregate that relies on time?

我正在尝试为计时应用程序建模。

通常当我有一个依赖于时间的 class 时,我可以提供一个重载的构造函数或方法,以便能够将时钟注入该方法或 class 并能够测试它行为。

如果我有一个命令需要能够将当前时间传递给一个事件,这在基于轴突的应用程序的集合中如何工作?

@Aggregate
@Slf4j
public class TimeCard {

  @AggregateIdentifier
  private String employeeName;
  private Instant clockInTime;

  public TimeCard() {
    //Axon requires empty constructor on aggregate
  }

  @CommandHandler
  public TimeCard(ClockInCommand cmd) {
    AggregateLifecycle.apply(new ClockInEvent(cmd.getEmployeeName(), Instant.now()));
  }

  @EventSourcingHandler
  public void on(ClockInEvent event) {
    this.employeeName = event.getEmployeeName();
    this.clockInTime = event.getClockInTime();
  }
}

似乎测试夹具通过提供提供时间的方法为我干净地处理了这个问题。这是我的测试方法:

@Test
void testClockInCommand() {
  testFixture.givenNoPriorActivity()
    .andGivenCurrentTime(clock.instant())
    .when(new ClockInCommand("GoldFlsh"))
    .expectEvents(new ClockInEvent("GoldFlsh", testFixture.currentTime()));
}

但我的事件确实有几分之一秒的差异。

Expected <2020-02-02T13:47:20.684344700Z> but got <2020-02-02T13:47:20.954347700Z>

处理此问题的最佳方法是什么?命令应该只从上游获取时间吗?或者我可以以某种方式注入时钟进行测试。

在聚合(和其他轴突类型)中依赖时间时,您可以使用 GenericEventMessage.clock,在大多数运行时配置中默认为 System.UTC。

Testfixture 将在测试期间将其覆盖为固定时间。更新 Instant.now() 的使用以使用此时钟。

@CommandHandler
public TimeCard(ClockInCommand cmd) {
  AggregateLifecycle.apply(new ClockInEvent(cmd.getEmployeeName(), GenericEventMessage.clock.instant()));
}