2012-06-26 149 views
3

我知道一个类似的问题已被问到,但我还没有找到明确的解决方案。我试图嘲笑一个大班的私人领域。私人领域得到实例在一些较早的方法,我试图单元测试引用该领域的后一种方法。嘲笑私人领域

所以我有一个较早的方法在我的课:

public bool validateAll(ref DataEntry[] oEntries, string sMediaPlanId, ITemplateGenerator oTempGen) 
{ 
    ... 
    // private field that I am trying to mock 
    this._sMediaPlanObjective = (MPWrapper.Instance).getMediaPlanObjective(sMediaPlanId); 
    ... 
} 

我试图单元测试引用私有字段的方法:

public bool validateFlightObjective(ref MPDataEntry oEntry) 
{ 
    ... 
    string entryFlightObjective = oEntry.getFlightObjective(); 
    string mediaPlanObjective = this._sMediaPlanObjective; 

    if (entryFlightObjective != mediaPlanObjective) 
    { 
    return false; 
    } 
    ... 

    return true;  
} 

假设我有一个大类,这只是我想测试的一种方法,有没有可能的方法来模拟这个私人领域?我缺少一些基本的东西,还是应该考虑其他方法?

+0

正如答案中所述,您可以(应该)通过一些重构努力来避免这种情况。如果你仍然不想这样做,你可以尝试一个更强大的模拟框架,如Typemock Isolator或者Moles。 – seldary

回答

4

你不能模拟什么这是私人的,静态的,或基本上 - 不可重写(这是作为免费的嘲讽库limitation)。

你通常在这种情况下做什么(当它出现的是private成员进行测试),被提取的private成员到一个单独的类,并inject它来测试类的依赖。

在你的情况,你确实需要提取创建_sMediaPlanObjective,这是这行代码:

this._sMediaPlanObjective = 
    (MPWrapper.Instance).getMediaPlanObjective(sMediaPlanId); 

对象,它提供getMediaPlanObjective方法应注射到你的测试类。如果你这样做,你可以简单地嘲笑这个对象,并告诉它返回_sMediaPlanObjective的模拟版本。

+0

这是否意味着必须调用validateAll()来设置私有成员的模拟版本,以便我可以测试validateFlightObjective()?或者,让一些公共/受保护的访问者设置私人成员是更好的做法。 –

+0

@SamuelHeaney:最有可能的。如果赋予私有字段在'validateAll'方法中完成* only *(并且不能在其他地方完成,那么在构造函数中,一旦注入了依赖关系),则需要调用它来设置模拟。仅为单元测试而添加额外的访问者应该是**最后的手段**。 –

0

没有理由在private字段上进行任何类型的测试。

使用一个对象可以引用public方法作为对象的API。 对象本身可以根据您对其执行的操作改变其状态 - 但它会反映在其他方法/访问DAL(DB/Registry/File /任何其他不在内存中的资源)中的方法

所以你的情况,你可以有一个单元测试这样的:

通话,你期望它初始化私有字段的方法和 -

  • 呼叫validateFlightObjective,你知道有一个参数根据_sMediaPlanObjective返回false“通缉成为国家“,并确认结果是错误的。

  • 调用validateFlightObjective带有一个参数,您知道必须根据_sMediaPlanObjective“想成为状态”返回true,并验证结果是否为真。

如果你看到它是很难测试这个对象,那么这可能是一个“嗅觉” - 也许你有一个以上的责任那里,你应该开始重构和阶级分裂,小班这将更容易测试

这有点长,但我希望这是有益的

+0

我不想测试私人领域本身。不调用初始化私有字段的方法违反了单元测试中行为的隔离?而且,调用它意味着需要调用其他几个需要顺序调用并访问数据库的方法。 –

0

可以使用JustMock框架。 例如:

double value = 0; 
var fakeFilterSetHelper = Mock.Create<FilterSetHelper>(Behavior.CallOriginal); 
Mock.NonPublic.Arrange<double>(fakeFilterSetHelper, memberName: "GetPriceRangeFromSession").Returns(value);