5

我正在开发一个具有与此类似的域模型的应用程序,其中 aLineItem既可以从 anOrder也可以从Shipment.

图表

如果我使用 AutoFixture 来生成,我怎样才能对和Order使用相同的集合?LineItemsorder.LineItemsorder.Shipments*.ItemShipments*.LineItem

理论上,应该通过以下测试:

var fullyShippedOrder = fixture.CreateAnonymous<Order>();
var shippedLineItems = fullyShippedOrder.Shipments
    .SelectMany(o => o.ItemShipment, (s, i) => i.LineItem)
    .Distinct();
Assert.EqualCollection(fullyShippedOrder.LineItems, shippedLineItems);

...虽然我也希望能够根据测试生成部分发货的订单。

(有一个可靠的论点是 Order 上的 line item 和 Shipment 上的 line item 是不同的东西,我不应该使用同一个类来表示它们。但是,我正在使用的数据来自遗留系统,对此无能为力。)

4

1 回答 1

5

正如您所说,您在测试中遇到的摩擦很可能是域模型中设计问题的标志。理想情况下,您应该听取您的测试并从根本上解决问题。但是,鉴于在这种情况下不可行,这里有一个解决方法。

您可以使用该方法将其配置为始终按固定顺序Fixture返回对象。LineItemRegister<T>(Func<T> creator)

这是一个打包在自定义项中的示例:

public class GenerateLineItemFromFixedSequence : ICustomization
{
    public void Customize(IFixture fixture)
    {
        var items = CreateFixedLineItemSequence(fixture);
        fixture.Register(() => GetRandomElementInSequence(items));
    }

    private static IEnumerable<LineItem> CreateFixedLineItemSequence(IFixture fixture)
    {
        return fixture.CreateAnonymous<LineItem[]>();
    }

    private static LineItem GetRandomElementInSequence(IEnumerable<LineItem> items)
    {
        var randomIndex = new Random().Next(0, items.Count());
        return items.ElementAt(randomIndex);
    }
}

为了在测试的上下文中应用此行为,只需将自定义添加到Fixture对象:

fixture.Customize(new GenerateLineItemFromFixedSequence());

同样,您可以创建其他自定义项,以生成LineItem处于不同状态的对象的固定序列,例如您提到的部分发货的订单,并在不同的测试中使用它们。

观察

有趣的是,这种定制可以是通用的,因为算法本身并没有与正在创建的对象的类型相耦合。这将有效地将其转化为一种战略

因此,通过引入通用参数来修改自定义:

public class GenerateFromFixedSequence<T> : ICustomization
{
    public void Customize(IFixture fixture)
    {
        var items = CreateFixedSequence(fixture);
        fixture.Register(() => GetRandomElementInSequence(items));
    }

    private static IEnumerable<T> CreateFixedSequence(IFixture fixture)
    {
        return fixture.CreateAnonymous<T[]>();
    }

    private static T GetRandomElementInSequence(IEnumerable<T> items)
    {
        var randomIndex = new Random().Next(0, items.Count());
        return items.ElementAt(randomIndex);
    }
}

将允许您将其用于不同的对象:

fixture.Customize(new GenerateFromFixedSequence<LineItem>());
fixture.Customize(new GenerateFromFixedSequence<Order>());
fixture.Customize(new GenerateFromFixedSequence<Shipment>());
于 2012-12-19T09:52:37.713 回答