【问题标题】:How to write unit tests around private methods如何围绕私有方法编写单元测试
【发布时间】:2013-05-25 21:07:44
【问题描述】:

我正在尝试对具有公共和私有方法的类进行单元测试,并且我想对已设置为私有(基础上受保护的抽象)的特定方法进行单元测试。我无法公开该方法,也不想通过整个过程来测试该方法,我只关心该方法的输入参数和返回是否符合预期。

我不想公开该方法,因为这个问题突出显示:

Making a private method public to unit test it...good idea?

我的问题是,测试私有方法的各种方法是什么,我应该支持哪种技术以及为什么?

我已阅读此问题 (How do you unit test private methods?),但想知道接受的答案是否仍然是最佳答案,或者多年后有更好的方法。

如果此问题与How do you unit test private methods? 重复,我将在此处添加我的评论并要求更新,请告知。

【问题讨论】:

标签: c# .net unit-testing nunit nsubstitute


【解决方案1】:

我已经阅读了这个问题(你如何对私有方法进行单元测试?)但是 想知道接受的答案是否仍然是最佳答案或 多年后有更好的方法。

我会避免接受的答案。

我可以长篇大论地测试公共接口而不用担心内部,但这可能不现实。

我可以看到两个直接选项:

  • 反思查看方法,有点像黑客,但至少你可以进行某种测试。这也可能是最容易快速开始工作的方法。
  • 使用类似策略模式的东西抽象私有方法行为并将行为注入对象本身(或在内部让对象new 手动提升相关策略)。然后可以独立测试这个单独的策略项。

也就是说,您不应该经常遇到这种情况。如果你这样做了,你需要退后一步,回顾一下你是如何设计你的课程的,并可能重新审视它们,以使它们更加开放和可测试。

【讨论】:

  • +1 感谢您的意见,我也考虑过反射,但希望尽可能避免它,因为我怀疑这需要相当大的努力?
  • @Monkieboy 如果你只为一小部分物品做这件事,那真的不多。当然,代码更冗长,并且不是强类型或其他任何东西,但您可能会认为这是一个不错的权衡。
【解决方案2】:

如果您无法通过公共方法有意义地测试类的私有方法,那么这表明该类的设计存在问题。如果很难测试类,因此您希望分解测试以测试其功能的子集,那么我建议将类分解成逻辑部分并单独测试。

也许您有机会重构代码,以便私有方法成为其他一些类的公共方法。一个很好的例子是一个类,它在一个计时器上安排一些工作,以便稍后处理。工作方法可能会被实现为私有方法,如果不安排计时器并等待它执行工作方法,则很难以简单的方式进行测试。在执行时间应该非常快的测试中并不理想。解决此问题的一种简单方法是将调度工作代码拆分为两个单独的类。私有工作方法然后成为 Worker 类的公共方法,使其非常容易测试。虽然拆分调度和工作代码意味着您将难以实现 100% 的覆盖率,但您至少会覆盖工作代码。解决此问题的一种方法是使用 Quartz.net 之类的东西来实现调度程序类,这样您就可以很容易地对调度程序和工作代码进行单元测试。

【讨论】:

  • +1 是的,你是对的,这可能表明存在一些设计缺陷,但我的理由是,为已经存在的功能位编写测试需要大量工作,这有点过时了我正在进行的当前更改的范围。我确实想对此进行全面测试,但现在不能这样做。
  • 您在这里的意见实际上是我同意的,因此会鼓励人们对这个答案进行投票,因此它确实得到了应有的重视,尽管在我的具体案例中无法遵循这些建议。
【解决方案3】:

使用反射。如果您不想自己弄乱反射,那么您可以使用位于 Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll 中的 Microsoft 的 PrivateObject 类。但是MSTest和NUnit配合有问题-Using both MSTest and NUnit?

【讨论】:

    【解决方案4】:

    在 VS 2005、2008 和 2010 中,您可能拥有私有访问器。您右键单击一个私有函数,然后选择“创建私有访问器”...

    在 VS 2012 中,这个功能不知何故消失了。唯一方便的方法是使用 PrivateObject。您可以查看 MSDN 以获取使用 PrivateObject 的示例。

    【讨论】:

      【解决方案5】:

      您希望能够在测试中调用您的私有方法并查看它是如何工作的吗?

      您可以从您的类派生并添加将调用您要测试的方法的公共方法。很简单。虽然我不建议测试私有方法。我想不出这样做的单一理由。我很想看到能改变我想法的例子。

      编辑:因为这个答案仍然有一些流量,所以我分享了这个链接。这篇博文是在我发布答案大约 4 年后创建的: https://enterprisecraftsmanship.com/posts/unit-testing-private-methods/

      【讨论】:

      • +1 是的,我同意,我真的不喜欢单独测试私有方法,因为如果调用方法以某种方式更改,它会在未来引入脆弱性,在这种情况下没有测试涵盖了这一点,但我认为我要做的实际上是继承并调用贯穿整个流程的基本实现,即使我将模拟很多内部结构并允许测试随着未来修订中发生的变化而发展。
      • 我最终所做的是从我想测试的类中派生出我的私有方法,捕获输入和输出并在我的测试中使用它们。
      • 你所做的甚至还有一个名字——“提取和覆盖”
      • 私有方法是完全有效的可测试对象,测试与访问级别无关,访问级别只是一种语言结构,测试是关于断言功能,无法访问功能是框架的限制.阅读这些 cmets 了解更多信息stackoverflow.com/a/249853/1441011
      【解决方案6】:

      如果您使用的是 VS 2005 或更高版本,请使用以下步骤

      1. 打开一个包含私有方法的源代码文件。
      2. 右键单击私有方法,然后选择创建单元测试。 这将显示“创建单元测试”对话框。在可见的树形结构中,只有私有方法的复选框被选中。
      3. (可选)在创建单元测试对话框中,您可以更改输出项目。您还可以单击“设置”重新配置生成单元测试的方式。
      4. 单击确定。 这将创建一个名为 VSCodeGenAccessors 的新文件,其中包含特殊的访问器方法,用于检索正在测试的类中私有实体的值。您可以在测试项目文件夹中的解决方案资源管理器中看到新文件。 如果您的测试项目在此之前没有单元测试,那么还会创建一个包含单元测试的源代码文件。与包含私有访问器的文件一样,包含单元测试的文件也在解决方案资源管理器的测试项目中可见。
      5. 打开包含单元测试的文件并滚动到私有方法的测试。找到标有 // TODO: cmets 的语句,并按照 cmets 中的说明完成它们。这有助于测试产生更准确的结果

      更多信息请参考this

      看起来它在内部使用反射来调用私有方法。但它有效。

      【讨论】:

        【解决方案7】:

        我实际上是来这里回答这个问题的,直到我意识到我不应该对私有方法进行单元测试。这样做的原因是,私有方法是进程中的一部分,是更大逻辑的一部分。

        单元测试旨在针对类的接口进行测试。这个想法是,我应该在以预期的方式使用我的课程时确保质量控制。因此,对私有方法进行单元测试是没有用的,因为它永远不会暴露给消费者(无论谁在实现)。您需要针对消费者可以使用您的类的案例进行单元测试。

        如果您发现自己绝对需要对私有的东西进行单元测试,您可能需要重新考虑该方法的位置,或者您的代码是如何分解的。我得出的结论是,如果我需要对私有方法进行单元测试,9/10 次它是可以包装到静态实用程序类中的方法。

        【讨论】:

          猜你喜欢
          • 2016-06-29
          • 1970-01-01
          • 1970-01-01
          • 2014-08-10
          • 2016-09-25
          • 1970-01-01
          • 2014-10-03
          相关资源
          最近更新 更多