是否可以为单元测试更改方法可见性?

时间:2010-02-25 00:00:58

标签: c# unit-testing

很多时候,我发现自己在将一个方法设为私有以防止某人在一个没有意义的上下文中调用它(或者会搞砸了所涉及对象的内部状态)或者将该方法公之于众(或者通常是内部的)以便将其暴露给单元测试组件。我只是想知道Stack Overflow社区对这种困境的看法是什么?

所以我想问题的确是,关注可测试性还是保持适当的封装更好?

最近我一直倾向于可测试性,因为大多数代码只会被一小群开发人员利用,但我想我会看到其他人的想法?

5 个答案:

答案 0 :(得分:23)

不能改变客户或用户可以看到的方法的方法可见性。这样做是丑陋的,黑客攻击,暴露了任何愚蠢的用户可能尝试使用和爆炸你的应用程序的方法......这是你不需要的责任。

您正在使用C#是吗?查看internals visible to属性类。 您可以将可测试方法声明为内部方法,并允许单元测试程序集访问内部。

答案 1 :(得分:16)

这取决于该方法是否是公共API的一部分。如果某个方法不属于公共API的一部分,但是从同一程序集中的其他类型公开调用,请使用internal,friend your unit test assembly,并对其进行单元测试。

但是,如果该方法不是/不应该是公共API的一部分,并且它不是由程序集内部的其他类型调用的,则不要直接测试它。它应该是受保护的或私有的,并且只能通过单元测试您的公共API来间接测试。如果您为类型的非公共(或应该是非公共的)成员编写单元测试,则将测试代码绑定到内部实现详细信息。

这是一种糟糕的耦合,增加了您所需的单元测试数量,在短期内(更多单元测试)以及长期增加工作量(更多测试维护和修改以响应重构内部实现细节)。测试非公共成员的另一个问题是您测试可能实际上不需要或使用的代码。找到死代码的一种很好的方法是,当您的公共API被100%覆盖时,任何单元测试都不会覆盖它。删除死代码是一种很好的方法,可以保持代码库的精简和平均,如果您不小心将自己的内容放入公共API,以及代码的哪些部分进行单元测试,则无法实现。

编辑: 作为一个快速的附加说明......使用正确设计的公共API,您可以非常有效地使用Microsoft PEX之类的工具自动生成全覆盖单元测试,以测试代码的每个执行路径。结合一些涵盖关键行为的手动编写的测试,任何未涵盖的内容都可以被视为死代码并被删除,您可以大大简化您的单元测试过程。

答案 2 :(得分:2)

这是一个普遍的想法。

通常最好通过测试调用它们的公共方法来测试私有方法(因此您不会显式测试私有方法)。但是,我知道有时候你真的想测试这些私有方法。

this question (Java)this question (.NET)的答案应该会有所帮助。

回答这个问题:不,为了测试,你不应该改变方法可见性。你通常不应该测试私有方法,当你这样做时,有更好的方法来做它。

答案 3 :(得分:1)

总的来说,我同意@jrista。但是,像往常一样,这取决于。

尝试使用遗留代码时,关键是要对其进行测试。之后,您可以添加新功能和现有错误的测试,重构以改进设计等。如果没有测试,这是有风险的。传统代码往往充斥着依赖性,并且通常极难进行测试。

Working Effectively with Legacy Code中,Michael Feathers提出了多种获取代码的技术。这些技术中的许多涉及破坏封装或使设计复杂化,并且作者对此有所了解。一旦测试到位,就可以安全地改进代码。

因此,对于遗留代码,请执行您必须执行的操作。

答案 4 :(得分:0)

在.NET中,您应该使用Accessors进行单元测试,甚至使用InternalsVisibleTo属性。访问器允许您访问类中的任何方法,即使它是私有的。它们甚至允许您使用空的模拟派生对象测试抽象类(请参阅“PrivateObject”类)。

基本上在您的测试项目中,您使用的是访问器类,而不是使用您要测试的方法的实际类。访问者类与“真实”类相同,除了测试项目的所有内容都是公开的。 Visual Studio可以为您生成访问器。

从不使类型更易于显示以便于单元测试。

IMO说你不应该对私人方法进行单元测试是错误的。单元测试对于回归测试具有特殊价值,并且没有理由不使用粒度单元测试对私有方法进行回归测试。