Unit testing 如何实例化聚合以测试其他聚合?

Unit testing 如何实例化聚合以测试其他聚合?,unit-testing,domain-driven-design,aggregateroot,axon,Unit Testing,Domain Driven Design,Aggregateroot,Axon,假设我有一个聚合,对于某些操作,它需要存在另一个聚合。假设我有一辆汽车和一个车库。可能有一个名为parkingare的命令,如下所示: public class ParkInGarage { @TargetAggregateIdentifier public final UUID carId; public final Garage garage; //... constructor omitted } 我已经说过,为了验证聚合的存在性,最好在命令中使用加

假设我有一个聚合,对于某些操作,它需要存在另一个聚合。假设我有一辆
汽车
和一个
车库
。可能有一个名为
parkingare
的命令,如下所示:

public class ParkInGarage {

    @TargetAggregateIdentifier
    public final UUID carId;

    public final Garage garage;

    //... constructor omitted
}
我已经说过,为了验证聚合的存在性,最好在命令中使用加载的聚合,因为这已经意味着它的存在(而不是传递
garageId

现在,当使用单元测试
汽车
时,我不能简单地通过说
newgarage(buildGarageCmd)
来实例化我的
车库
。它会说:

java.lang.IllegalStateException:如果没有活动的作用域,则无法请求当前作用域

因为没有建立基础设施。 我应该如何测试这种情况,还是应该以不同的方式设计聚合

抽象的、真实的示例 我正在使用的聚合根可能有一个对自身的引用,以形成所述聚合根的树结构。让我们称之为
节点

@Aggregate
public class Node {
    private Node parentNode;
}
创建时,我可以将一个
可选的
作为父项传递,或者稍后使用单独的命令设置父项。父级是应该定义为实例还是按ID定义是问题的一部分

public class AttachNodeCmd {
    @TargetAggregateIdentifier
    public final UUID nodeId;
    public final Optional<Node> parentNode;
}

在某些时候,需要实例化父级来执行这些检查。这可以通过在命令中提供聚合实例(不鼓励)来实现,也可以通过向命令处理程序提供
存储库
节点ID
来实现,这是聚合本身,也是不鼓励的。目前,我还没有找到一种正确的方法来实现这一点,更进一步,我还没有找到一种方法来测试它。

我不会将AR实例放在命令中。命令模式应该是稳定的,并且易于序列化/重新序列化,因为它们是消息契约

相反,您可以做的是解析命令处理程序中的依赖项

//ParkInGarage command handler
Garage garage = garageRepository.garageOfId(command.garageId);
Car car = carRepository.carOfId(command.carId);

car.parkIn(garage);

我根本不知道Axon框架,但现在应该比较容易测试。

我认为@plalx让您走上了正确的道路。命令是API/消息契约的一部分,在其中公开聚合并不是什么好主意。 此外,我想指出的是,Axon中的
aggregateTextures
用于测试单个聚合,而不是聚合之间的操作协调


聚合/有界上下文之间的协调通常是您看到传奇即将上演的地方。现在老实说,我有点怀疑这个用例是否证明了一个传奇的合理性,但是我可以想象如果
parkcaringaragecomand
失败是因为
Garage
聚合已满(例如),那么您需要通过另一个命令指示
Car
聚合,告诉它这是不可能的。Axon中设置的Saga可能会帮助您实现这一点,因为您可以轻松捕获(1)处理命令时出现的异常或(2)处理通知操作未成功的事件。

这是一个不错的解决方案,但是Axon不允许您在命令处理程序中注入存储库,也不鼓励您在聚合中使用存储库,因为加载需要时间,并且在聚合被锁定时会增加并发修改的机会。你的建议很有道理,但我担心在这种情况下它更像是一个框架限制。这似乎是一个奇怪的框架限制,因为解决命令处理程序/应用程序服务中的依赖关系是DDD从业者的行业标准。ParkCarInGarageCommand将指向哪个聚合?据我所知,传奇只是由事件开始的。因此,最初必须处理该命令。“其他东西”如何获得所需聚合的实例?你能提供一个例子吗?我已经编辑了我的帖子,为我试图做和测试的事情提供了一个更具体的例子。如果Axon能够提供一个示例解决方案,那就太好了,因为目前我在文档中找不到任何提示。我确信这是一个常见的问题。另外,如果我不能在命令或事件中有任何聚合(成员),我如何使用对象指针重建聚合根,以仅使用ID聚合成员?所有这些规则都是难以置信的限制。任何组件/单例/bean都可以有
@CommandHandler
注释。因此,您可以添加一个单独的单例来处理
ParkCarInGarageCommand
,例如,它反过来发送命令。如果您想使用Saga,那么使用,它应该从一些事件开始,然后可以将命令发布到它所绑定的聚合。这意味着你将有一个不同的操作起点,我很难告诉你它是什么,因为我不熟悉你的领域。谢谢,我想我已经掌握了窍门。树“一致性边界”的解决方案是引入另一个实体作为聚合根并保护树结构不变。所有操作都是通过它执行的,例如添加节点和链接节点。在用于添加节点的事件(寻源)处理程序中,新节点正在那里实例化。这消除了对存储库或存在性检查的需要。
//ParkInGarage command handler
Garage garage = garageRepository.garageOfId(command.garageId);
Car car = carRepository.carOfId(command.carId);

car.parkIn(garage);