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

时间:2018-11-15 15:02:00

标签: unit-testing domain-driven-design aggregateroot axon

假设我有一个集合,对于某些操作,它需要存在另一个集合。假设我有一个car和一个garage。可能有一个名为ParkInGarage的命令,如下所示:

public class ParkInGarage {

    @TargetAggregateIdentifier
    public final UUID carId;

    public final Garage garage;

    //... constructor omitted
}

我已经read验证聚合的存在,在命令中使用加载的聚合是一种好习惯,因为这已经暗示了聚合的存在(而不是传递garageId)。

现在,当使用Axon's fixturesCar进行单元测试时,我不能简单地说出Garage来实例化new Garage(buildGarageCmd)。它会说:

  

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

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

抽象的真实示例

我正在使用的聚合根可能会引用自己以形成所述聚合根的树结构。我们称之为Node

@Aggregate
public class Node {
    private Node parentNode;
}

创建后,我可以将Optional<Node>作为父级传递,或者稍后使用单独的命令设置父级。问题的一部分是将父对象定义为实例还是按ID定义。

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

在命令处理程序中,我需要检查将节点附加到给定的父级是否会引入一个循环(该结构应该是树,而不是普通图)。

@CommandHandler
public Node(AttachNodeCmd command) {
    if (command.parentNode.isPresent()) {
        Node currentNode = command.parentNode.get();
        while (currentNode != null) {
            if (currentNode.equals(this)) throw new RecursionException();
            currentNode = currentNode.parentNode.orElse(null);
        }
    }

    //Accept the command by applying() an Event
}

在某些时候,需要实例化父级以执行那些检查。这可以通过在命令中提供聚合实例(不推荐使用)来完成,也可以通过向命令处理程序提供Repository<Node>nodeId来完成,而该命令处理程序本身就是聚合的并且也不鼓励使用。目前,我没有找到正确的方法来进行此操作,并且没有进一步测试的方法。

2 个答案:

答案 0 :(得分:2)

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

您可以做的是解决命令处理程序中的依赖项。

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

car.parkIn(garage);

我一点都不了解Axon Framework,但是现在应该相对容易测试。

答案 1 :(得分:1)

我认为@plalx使您步入正轨。命令是您的API /消息合约的一部分,而在其中公开聚合并不是一个好主意。 另外,我想指出Axon中的AggregateFixtures可以测试单个聚合,而不是聚合之间的操作协调。

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