【问题标题】:Is it ok to change method visibility for the sake of unit testing?为了单元测试而改变方法可见性是否可以?
【发布时间】:2010-02-25 00:00:58
【问题描述】:

很多时候我发现自己在将方法设为私有以防止有人在没有意义的上下文中调用它(或会搞砸所涉及对象的内部状态)或将方法设为公开(或通常是内部的),以便将其暴露给单元测试程序集。我只是想知道 Stack Overflow 社区如何看待这种困境?

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

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

【问题讨论】:

    标签: c# unit-testing


    【解决方案1】:

    不能更改客户或用户可以看到的方法的可见性。这样做很丑陋,是一种黑客行为,暴露了任何愚蠢的用户都可以尝试使用并炸毁您的应用程序的方法……这是您不需要的责任。

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

    【讨论】:

    • 从我的问题中可以看出,我知道我可以创建一个内部方法,并且只对程序集中的其他类(或朋友程序集)可见。我发现有时即使是内部方法也会使对象模型看起来不那么简洁或经过深思熟虑的那些在同一程序集中开发的人,因此问题的原因:)
    【解决方案2】:

    这取决于方法是否是公共 API 的一部分。如果方法不属于公共 API 的一部分,但在同一程序集中的其他类型中被公开调用,请使用 internal,为您的单元测试程序集加好友,然后对其进行单元测试。

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

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

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

    【讨论】:

    • 您找到了我的问题的症结所在 - 使内部方法仍然暴露太多,因为这些是程序集中其他类不应该调用的方法。我非常同意你的想法,即测试应该是非公共方法的测试代码与实现的绑定过于紧密。
    • @Eric:然后您记录并强制执行不应调用这些方法。 VS2010 的新层图功能可能会有所帮助,因为可以限制一层与另一层的交互方式——这些限制可以在构建期间强制执行。
    • 很高兴为您服务。 :) 我添加了您可能感兴趣的有关 PEX 的更新。
    【解决方案3】:

    这是一个普遍的想法。

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

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

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

    【讨论】:

      【解决方案4】:

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

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

      Working Effectively with Legacy Code 中,Michael Feathers 提出了多种用于测试代码的技术。其中许多技术涉及破坏封装或使设计复杂化,而作者对此很清楚。一旦测试到位,就可以安全地改进代码。

      所以对于遗留代码,做你必须做的。

      【讨论】:

        【解决方案5】:

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

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

        永远不要让类型更明显以方便单元测试。

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

        【讨论】:

          猜你喜欢
          • 2010-12-03
          • 1970-01-01
          • 2013-03-18
          • 2013-07-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-07-07
          相关资源
          最近更新 更多