Visual Studio允许通过自动生成的访问器类对私有方法进行单元测试 . 我编写了一个成功编译的私有方法的测试,但它在运行时失败了 . 一个相当小的代码和测试版本是:
//in project MyProj
class TypeA
{
private List<TypeB> myList = new List<TypeB>();
private class TypeB
{
public TypeB()
{
}
}
public TypeA()
{
}
private void MyFunc()
{
//processing of myList that changes state of instance
}
}
//in project TestMyProj
public void MyFuncTest()
{
TypeA_Accessor target = new TypeA_Accessor();
//following line is the one that throws exception
target.myList.Add(new TypeA_Accessor.TypeB());
target.MyFunc();
//check changed state of target
}
运行时错误是:
Object of type System.Collections.Generic.List`1[MyProj.TypeA.TypeA_Accessor+TypeB]' cannot be converted to type 'System.Collections.Generic.List`1[MyProj.TypeA.TypeA+TypeB]'.
根据intellisense - 因此我猜编译器 - 目标是TypeA_Accessor类型 . 但在运行时它的类型为TypeA,因此列表添加失败 .
有什么办法可以阻止这个错误吗?或者,或许更有可能的是,其他人有什么其他建议(我预测可能“不测试私有方法”和“没有单元测试操纵对象的状态”) .
8 回答
是的,不要测试私有方法....单元测试的想法是通过公共'API'测试单元 .
如果您发现需要测试很多私有行为,那么很可能您在要测试的类中隐藏了一个新的“类”,将其解压缩并通过其公共接口进行测试 .
一条建议/思考工具.....有一种想法,任何方法都不应该是私密的 . 这意味着所有方法都应该存在于对象的公共接口上....如果您觉得需要将其设置为私有,则很可能存在于另一个对象上 .
这条建议在实践中并没有很好的解决,但它的建议大多是好的,而且往往会促使人们将对象分解成更小的对象 .
你可以使用PrivateObject Class
“没有什么叫做标准或最佳实践,可能它们只是流行的观点” .
同样适用于此讨论 .
这一切都取决于你认为是一个单位,如果你认为UNIT是一个类,那么你只会点击公共方法 . 如果你认为UNIT是代码行,打私人方法不会让你感到内疚 .
如果要调用私有方法,可以使用"PrivateObject"类并调用invoke方法 . 您可以观看此深入视频(http://www.youtube.com/watch?v=Vq6Gcs9LrPQ),其中显示了如何使用"PrivateObject",还讨论了私有方法的测试是否合乎逻辑 .
这里的另一个想法是将测试扩展到“内部”类/方法,给出更多白盒感测的测试 . 您可以在程序集上使用InternalsVisibleToAttribute将这些内容公开给单独的单元测试模块 .
结合密封类,您可以进行这样的封装,即测试方法只能从您的方法的unittest程序集中看到 . 考虑密封类中的受保护方法事实上是私有的 .
和单元测试:
测试私有方法的一种方法是通过反射 . 这也适用于NUnit和XUnit:
您可以围绕包含要测试的私有方法的类创建包装类 . 这个包装类包含一个名为Call_MyPrivateFunction的公共方法,该方法又调用其基类的私有函数 .
请注意,方法的访问级别应更改为[protected]
代码示例:
单元测试代码可能如下所示:
TL;DR: 将私有方法解压缩到另一个类,对该类进行测试;了解更多关于SRP原则(单一责任原则)
看来你需要将
private
方法提取到另一个类;在这应该是public
. 您应该测试另一个类的public
方法,而不是尝试测试private
方法 .我们有以下场景:
我们需要测试
_someLogic
的逻辑;但似乎Class A
承担的角色超出了它的需要(违反了SRP原则);只需重构为两个类这样
someLogic
可以在A2上测试;在A1中只创建一些假的A2然后注入构造函数来测试A2被调用到名为someLogic
的函数 .在VS 2005/2008中,您可以使用private accessor来测试私有成员,但这种方式在VS的后续版本中是 disappear