2012-03-07 99 views
5

假设我有几个OrderProcessor s,它们中的每一个都有不同的处理顺序。
哪些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

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

你会做这样的事情在你的AssemblyInfo.cs文件:

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

虽然你可能会说,你的单元测试不一定在乎你的私人领域类。也许最好是将值传递给工厂方法,并在接口上调用某种方法(假设Calculate()或类似方法)时为预期结果编写单元测试。

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

这些是我在编写类似代码时通常采用的方法,但是有很多不同的方法来解决这样的问题。我会建议搞清楚你会在单元测试中获得最大的价值,并根据这个来写。

1

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

+1

虽然这是好主意似乎有理由想知道正在使用正确的折扣百分比,否则有人可以修改代码以使两个顶部路径返回'discountPercentages.FullDiscountPercentage',没有人会知道,一下子人就开始得到充分的折扣,而不是温和的一个 – 2012-03-07 18:16:10

+0

好,把DiscountOrderProcessor创建一个虚拟方法,并确保它被称为根据您厂的逻辑适当的参数。 – PatrickSteele 2012-03-07 18:39:11

+0

我将不得不同意帕特里克。这听起来像你正在冒险从单元测试到集成测试(这也很重要)。单元测试是针对一个逻辑单元的,每个订单处理器都应该有自己的单元测试。 – 2013-10-30 21:40:16

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),这样你可以询问他们。

,你可以把返回的对象,并检查其是否正确应用折扣的一些对象,你传递给它。

就我个人而言,我会去制作属性内部,但它取决于对象如何交互,如果将模拟对象传递给折扣订单处理器并验证其正确执行操作很简单,那么这可能是一个解决方案更好