单元测试工厂方法

时间:2012-03-07 17:31:50

标签: unit-testing nunit moq

假设我有几个OrderProcessor,每个都处理一个不同的订单 决定使用哪个OrderProcessor根据Order对象的属性完成,并由工厂方法完成,如下所示:

public IOrderProcessor CreateOrderProcessor(IOrdersRepository repository, Order order, DiscountPercentages discountPercentages)
{
    if (order.Amount > 5 && order.Unit.Price < 8)
    {
        return new DiscountOrderProcessor(repository, order, discountPercentages.FullDiscountPercentage);
    }

    if (order.Amount < 5)
    {
        // Offer a more modest discount
        return new DiscountOrderProcessor(repository, order, discountPercentages.ModestDiscountPercentage);
    }

    return new OutrageousPriceOrderProcessor(repository, order);
}

现在,我的问题是我要验证返回的OrderProcessor是否收到了正确的参数(例如正确的折扣百分比)。
但是,这些属性在OrderProcessor实体上不公开。

您如何建议我处理这种情况?

我能够提出的唯一解决方案是制作OrderProcessor公开的折扣百分比属性,但仅仅为了进行单元测试,这似乎是一种过度杀伤......

3 个答案:

答案 0 :(得分:3)

解决此问题的一种方法是将要测试的字段更改为内部而非私有,然后将项目的内部设置对测试项目可见。你可以在这里阅读:http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx

你可以在AssemblyInfo.cs文件中执行类似的操作:

[assembly:InternalsVisibleTo("Orders.Tests")]

虽然你可以说你的单元测试不一定关心你的私人领域。也许最好将值传递给factory方法,并在接口上调用某些方法(假设Calculate()或类似的东西)时为预期结果编写单元测试。

或者另一种方法是对具体类型(DiscountOrderProcessor等)进行单元测试,并从公共方法/属性确认它们的返回值。然后为工厂方法编写单元测试,它正确返回正确类型的接口实现。

这些是我在编写类似代码时经常采用的方法,但是有很多不同的方法可以解决这样的问题。我建议找出你在单元测试中获得最大价值的地方并根据它写出来。

答案 1 :(得分:1)

如果折扣百分比不公开,那么它不是IOrderProcessor合同的一部分,因此不需要进行验证。只需为DiscountOrderProcessor提供一组单元测试,以验证它是否根据通过构造函数传递的折扣百分比正确计算折扣。

答案 2 :(得分:0)

我看到你有几个选择。你可以创建DiscountOrderProcessor的专业化:

public class FullDiscountOrderProcessor : DiscountOrderProcessor
{
    public FullDiscountOrderProcessor(IOrdersRepository repository, Order order):base(repository,order,discountPercentages.FullDiscountPercentage)
    {}
}

public class ModestDiscountOrderProcessor : DiscountOrderProcessor
{
    public ModestDiscountOrderProcessor (IOrdersRepository repository, Order order):base(repository,order,discountPercentages.ModestDiscountPercentage)
    {}
}

并检查返回的正确类型。

你可以传入一个工厂来创建只需要一定金额的DiscountOrderProcessor,然后你就可以检查这是用正确的参数调用的。

您可以提供一个虚拟方法来创建DiscountOrderProcessor并检查是否使用正确的参数进行调用。

我非常喜欢个人的第一个选项,但所有这些方法都遇到了同样的问题,最终你无法检查实际值,所以有人可能会改变你的折扣金额,你不会知道。即使是第一种方法,你最终也无法测试应用于FullDiscountOrderProcessor的值是什么。

您需要检查离开的实际值:

您可以将属性设为公共(或内部 - 使用InternalsVisibleTo),以便您可以查询它们。

您可以获取返回的对象并检查它是否正确地将折扣应用于您传递给它的某个对象。

就我个人而言,我会把属性设置为内部,但这取决于对象如何交互,如果将模拟对象传递给折扣订单处理器并验证它是否正确操作很简单那么这可能会更好溶液