【问题标题】:How Can I Test Aggregate if ID is randomly generated?如果 ID 是随机生成的,我如何测试聚合?
【发布时间】:2020-02-02 17:29:12
【问题描述】:

这可能更像是一个设计问题,但我有一个通过命令生成的聚合成员,并且需要能够测试在命令运行的情况下是否生成了事件。

但是,我没有看到任何明显的方法可以在 TestFixture 框架中对事件的一个字段进行 anyString 匹配。

在创建时聚合生成 ID 是“不好的做法”吗?是否应该在聚合之外生成 ID?

@AggregateMember(eventForwardingMode = ForwardMatchingInstances.class)
private List<TimeCardEntry> timeCardEntries = new ArrayList<>();

data class ClockInCommand(@TargetAggregateIdentifier val employeeName: String)

@CommandHandler
public TimeCard(ClockInCommand cmd) {
  apply(new ClockInEvent(cmd.getEmployeeName(),
      GenericEventMessage.clock.instant(),
      UUID.randomUUID().toString()));


@EventSourcingHandler
public void on(ClockInEvent event) {
  this.employeeName = event.getEmployeeName();
  timeCardEntries.add(new TimeCardEntry(event.getTimeCardEntryId(), event.getTime()));
}

@Data
public class TimeCardEntry {

  @EntityId
  private final String timeCardEntryId;
  private final Instant clockInTime;
  private Instant clockOutTime;

  @EventSourcingHandler
  public void on(ClockOutEvent event) {
    this.clockOutTime = event.getTime();
  }

  private boolean isClockedIn() {
    return clockOutTime != null;
  }
}

@ParameterizedTest
@MethodSource(value = "randomEmployeeName")
void testClockInCommand(String employeeName) {
    testFixture.givenNoPriorActivity()
            .when(new ClockInCommand(employeeName))
            .expectEvents(new ClockInEvent(employeeName, testFixture.currentTime(), "Any-String-Works"));
}

【问题讨论】:

    标签: java domain-driven-design axon


    【解决方案1】:

    在创建时聚合生成 ID 是“不好的做法”吗?是否应该在聚合之外生成 ID?

    随机数很像时钟 - 它们是共享可变状态的一种形式。换句话说,它们是imperative shell 的关注点,而不是功能核心的关注点。

    这通常对您的域模型意味着随机性作为参数传入,而不是由聚合本身产生。这可能意味着将 ID 生成器传递给域模型,甚至在应用程序中生成 id 并传入生成的标识符 as a value

    因此,在我们的单元测试中,我们将目标应用程序提供的随机生成器替换为测试提供的“随机”生成器——因为测试控制了生成器,使用的标识符变得确定性,因此您可以更多轻松解决它。

    如果您对将随机生成器作为域模型 API 的一部分不满意,另一种选择是将其作为测试接口的一部分公开。

    // We don't necessarily worry about testing this version, it is "too simple to break"
    void doSomethingCool(...) {
        doSomethingCool(ID.new, ...);
    }
    
    // Unit tests measure this function instead, which is easier to test and has
    // all of the complicated logic
    void doSomethingCool(ID id, ...) {
        // ...
    }
    

    【讨论】:

    • 感谢您分享这些参考资料。很有见地。
    猜你喜欢
    • 2021-06-22
    • 1970-01-01
    • 2018-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-11
    相关资源
    最近更新 更多