我目前参与了与C#开发 - 下面是一些背景:我们与我们的客户端应用程序实现MVP和我们有规定,任何方法应该有一个圈复杂度大于5。这就导致了很多小的私有方法中圈规则它们一般负责一两件事。
我的问题是关于单元测试类:
通过公共方法测试私有实现是所有罚款...我没有贯彻这是一个问题。
但是......怎么样了以下情况:
实施例1处理异步数据retrival请求的结果(回调方法不应该公共纯粹用于测试)
实例2的事件,其确实的操作(如更新查看标签的文本-傻的例子,我知道...)
例3您正在使用第三方框架,允许您通过重写受保护的虚拟方法(从公共的方法来这些虚拟方法的路径通常被视为黑箱编程扩展,将有该框架提供了各种依赖关系的你不想知道)
上面的例子并不在我看来是设计不良的结果。 他们也不会出现将是候选人在隔离移动到一个单独的类测试,这种方法将失去他们的背景。
隐而不宣的人对此有什么看法吗?
干杯,杰森
编辑:我不认为我是在我原来的问题很清楚-我可以测试使用访问私有方法和使用TypeMock模拟出呼叫/方法。 这是没有问题的。 这个问题是测试事情,不需要公开,或不能公开。
我不想让代码公开测试的缘故,因为它会带来安全漏洞(只发布一个接口来隐藏这是不是一种选择,因为任何人都可以只投的对象回到原来的类型,并可以访问我的东西不希望他们)
这被重构到另一个类的测试代码是好的 - 但可能会失去环境。 我一直认为它不好的做法,有可能含有的代码锅,没有特定的上下文“助手”类 - (这里想SRP)。 我真的不认为这既适用于事件处理程序。
我很高兴被证明是错误的 - 我只是不能确定如何测试这个功能! 我一直头脑的,如果它能够打破或改变 - 测试。
干杯,杰森
Answer 1:
克里斯还指出,它是标准的做法,只有单元测试公有方法。 这是因为,作为该对象的消费者,你只关心的是公开提供给您。 而且,从理论上讲,与边缘的情况下适当的单元测试可以充分行使他们所有的私有方法的依赖。
话虽这么说,我觉得有几次在那里直接编写单元测试针对私有方法是非常有用的,并解释最简洁的,通过你的单元测试,一些比较复杂的方案或可能遇到的边缘情况。
如果是这样的话,你可以使用反射调用还是私有方法。
MyClass obj = new MyClass();
MethodInfo methodInfo = obj.GetType().GetMethod("MethodName", BindingFlags.Instance | BindingFlags.NonPublic);
object result = methodInfo.Invoke(obj, new object[] { "asdf", 1, 2 });
// assert your expected result against the one above
Answer 2:
我们有规定,任何方法应该有一个圈复杂度大于5一圈规则
我喜欢这样的规则。
问题的关键是,私有方法是实施细节 。 他们如有更改/重构。 你要测试的公共接口。
如果你有一个复杂的逻辑私有方法,考虑重构出来成一个单独的类。 这也可以帮助保持圈复杂度降低。 另一种方法是使该方法内使用InternalsVisibleTo(在克里斯的答案的链接之一提到)。
渔获量往往进来当你在私有方法引用的外部依赖。 在大多数情况下,你可以使用的技术,如依赖注入解耦你的类。 对于与第三方框架的例子,这可能是困难的。 我想尝试第一次重构设计分离第三方的依赖。 如果这是不可能的,可以考虑使用Typemock隔离 。 我没有用它,但它的主要特点是能“模拟”了私人,静等方法。
类是黑盒子。 测试他们的方式。
编辑:我会尽量给杰森的评论作出回应对我的回答和编辑原来的问题。 首先,我认为SRP 朝着更加类推,从他们不走。 是的,瑞士军刀辅助类,最好避免。 但是关于一类什么设计用来处理异步操作? 或数据检索类? 这些是原始类的责任的一部分,或者他们是否分开?
例如,假设您将这个逻辑到另一个类(可能是内部)。 这个类实现了异步设计模式 ,允许呼叫者选择,如果方法同步或异步调用。 单元测试或集成测试的编写对同步方法。 异步调用使用一个标准的模式,具有低复杂度; 我们没有测试这些(除了在验收测试)。 如果异步类是内部的,使用InternalsVisibleTo进行测试。
Answer 3:
实在是只有两个需要考虑的情况:
- 专用代码被调用时,直接或间接地从公共代码和
- 专用代码是不是公共代码调用。
在第一种情况下,专用代码会自动被其行使该调用私有代码市民代码测试的测试,因此没有必要测试专用代码。 而在第二种情况下,专用代码不能在所有调用,因此它应该被删除,未经测试。
人机工程学:没有必要明确测试专用代码。
需要注意的是,当你做TDD是不可能的未经测试的私有代码,甚至存在。 因为当你做TDD,私人代码可以出现的唯一途径,是通过提取{方法|类| ...}重构公共代码。 而且是的重构,顾名思义,行为保留,因此测试覆盖保留。 而公共代码可以出现的唯一途径是作为一个失败的测试结果。 如果市民代码只能出现在已测试的代码作为一个失败的测试结果,以及私人码只能显示为通过行为保留重构公共代码被提取出的结果,它遵循的是未经测试的私有代码永远不会出现。
Answer 4:
在我所有的单元测试,我从来没有打扰测试private
功能。 我通常只是测试public
职能。 这与黑盒测试方法一起去。
你是正确的,你真的,除非你暴露私有类无法测试私有函数。
如果你的“测试独立的类”是在同一个组件,您可以选择使用内部,而不是私人的。 这暴露了内部的方法来你的代码,但他们的方法将无法访问到您的装配不编码。
编辑:对于这个话题我碰上了SO搜索这个问题 。 最投票的答案是类似我的反应。
Answer 5:
从TDD人谁已经在C#中被敲打周围的几个要点:
1)如果你面向接口编程,然后一类是不是在接口的任何方法是有效的私有。 您可能会发现这是一个更好的办法,以促进可测试性和使用接口以及一个更好的办法。 测试这些公共成员。
2)那些小的辅助方法,可以更准确地属于一些其他类。 寻找功能羡慕。 什么可能不是合理的原始类的私有成员(在你发现它)可能是它羡慕类的合理公共方法。 在新的类作为公共成员测试这些。
3)如果您检查的一些小私有方法,你可能会发现他们有凝聚力。 他们可能代表一个较小的类的兴趣从原来的类分开。 如果是这样,那类可以有所有公共方法,但可以将持有的原始类的私有成员或者是创建和销毁功能。 在新的类作为公共成员测试这些。
4)你可以从原来的,在它是一个简单的任务,以创建一个什么都不做的新的公共方法,但调用的时候,私有方法推导出“可测试的”类。 可测试类是测试框架的一部分,而不是生产代码的一部分,所以它是很酷它具有特殊的访问。 测试中测试框架,就好像它是公开的。
所有这些都让它非常容易有对当前私有helper方法的方法测试,不会弄乱方式智能感知的作品。
Answer 6:
有一些伟大的答案在这里,我基本上与反复建议,同意给予萌芽新类。 对于示例3,然而,有一个偷偷摸摸的,简单的方法:
例3您正在使用第三方框架,允许您通过重写受保护的虚拟方法(从公共的方法来这些虚拟方法的路径通常被视为黑箱编程扩展,并有各种的框架提供了相关性你不想知道)
假设MyClass的延伸FrameworkClass。 有MyTestableClass延长MyClass的,然后提供MyTestableClass公共方法暴露,你需要的MyClass保护方法。 不是一个伟大的实践 - 这是一种不良的设计促成者 - 但有时是有用的,非常简单。
Answer 7:
将存取器文件? http://msdn.microsoft.com/en-us/library/bb514191.aspx我从来没有直接与他们合作,但我知道一个同事用它们来测试一些Windows窗体私有方法。
Answer 8:
有几个人回应说,私有方法不应该直接测试,或者他们应该被移动到另一个类。 虽然我认为这是件好事,有时它只是不值得。 虽然我原则上同意这种说法,我发现,这是该CNA被打破,以节省时间没有负面影响的规则之一。 如果函数是小/简单创建另一个类和测试类的开销是矫枉过正。 我将这些私有方法公开,但随后没有将它们添加到该接口。 消费者之类的这种方式(谁应该只通过我的IoC库越来越接口)将不会意外地使用它们,但它们可用于测试。
现在,在回调的情况下,这就是制作私有财产公开可以测试一个更容易编写和维护一个很好的例子。 举例来说,如果A类传递回调到B级,我会作出这样的回调类A的公共财产A类一个测试使用存根实现对B中记录传入的回调。然后,测试验证的回调在适当的条件下传递到B中。 然后对类A A单独的测试可以直接调用回调,验证它具有适当的副作用。
我觉得这个方法能很好的完成验证异步行为,我已经在一些JavaScript测试和一些LUA测试已经做了。 好处是,我有两个简单的小测试(一个验证回调设置,一个验证它的行为如预期)。 如果你尽量保持回调私人那么测试验证回调的行为有很多的设置来做,而设置将与行为,应在其他试验重叠。 坏的耦合。
我知道,它不是很漂亮,但我觉得它工作得很好。
Answer 9:
我承认,当最近写单元测试的C#我发现很多我知道的Java并没有真正适用的招数(在我的情况下,它是测试的内部类)。
例如1,如果你能假/嘲笑数据检索处理程序,你可以得到通过伪造的访问回调。 (其它大多数语言我知道,利用回调也往往不能使他们私有的)。
例如2我会去了解一下射击测试处理该事件。
实施例3是模板的形式,其在其他语言中存在的一个例子。 我已经看到了两种方法可以做到这一点:
测试全班反正(或至少它的相关件)。 在抽象基类本身自带的测试,或整体类是不是太复杂这尤其适用于个案。 在Java中,如果我在写AbstractList中的扩展名,例如我可能做到这一点。 这也可能是这种情况,如果是通过重构所生成的模板图案。
有额外的钩子,允许直接调用保护方法再次扩展类。
Answer 10:
不要测试私有代码,否则你会后悔后,当它的时间来重构。 然后,你会做像乔尔和博客有关TDD是如何工作太多,因为你不断地与你的代码重构你的测试。
有技术(嘲笑,存根)做适当的黑盒测试。 看看他们。
Answer 11:
这是引入测试时,很早就出现的问题。 解决这个问题的最好方法是黑盒测试 (如上所述),并按照单一职责原则 。 如果每个类的仅只有一个理由去改变,他们应该很容易测试他们的行为,而在他们的私有方法获得。
SRP - 维基百科 / PDF
这也导致了更强大和适应性代码为单一职责原则实际上只是说,你的类应该具有较高的凝聚力 。
Answer 12:
在C#中,你可以使用AssemblyInfo.cs中的属性:
[assembly: InternalsVisibleTo("Worker.Tests")]
只要选中内部私人方法,以及测试项目仍将看到的方法。 简单! 玩家可以不断的封装和测试有,没有所有的TDD废话。
文章来源: Unit testing private code [duplicate]