【问题标题】:Unit tests in same class (with conditional compilation)?同一类中的单元测试(使用条件编译)?
【发布时间】:2012-06-14 15:27:38
【问题描述】:

我知道(并同意)将单元测试放在单独的程序集中的常见论点。但是,最近我遇到了一些我真的想测试私有方法的情况。所讨论的幕后逻辑非常复杂,以至于测试公共和内部接口并不能完全完成工作。对类的公共接口的测试感觉过度劳累,我看到一些针对私有接口的测试可以更简单有效地完成工作。

过去,我通过制作我需要测试的东西protected,并创建一个我可以在测试框架中使用它的子类来解决这些情况。但这在应该是sealed 的类上效果不佳。更不用说用所有的脚手架来膨胀测试框架了。

所以我正在考虑这样做:在班级中放置一些测试,在那里他们可以得到私人成员。但是使用“#if DEBUG”将它们排除在生产代码之外。

这看起来是个好主意吗?

【问题讨论】:

  • 如果内部逻辑这么复杂,可能私有方法需要重构为单独的类。
  • 延伸阅读:How do you unit test private methods? 忽略标记的答案。
  • @Joe 我同意这是一个非常重要的设计原则。但每一个“也许”都有它的“也许不是”。这是“不”的情况之一。
  • @SeanU 如果这只是一次性的,那么反射是一个足够好“较小的邪恶”。
  • @Sean,好的,但是您问的是一个一般性问题,一般性的答案是寻求更可测试的设计。也许通过重构私有的东西,也许通过解封和使用受保护的东西。但是你的提议当然会奏效,任何规模的所有项目最终都会在某个地方出现丑陋的黑客行为,所以我不会担心......

标签: c# .net unit-testing


【解决方案1】:

在任何人问之前...

解决方案 OP 的问题是将 IoC 与 DI 正确结合,并完全消除测试私有方法的需要(如 Joel Martinez noted)。正如multiple times 所提到的,对私有成员进行单元测试不是要走的路

然而,有时您只是不能更改代码(遗留系统、破坏性更改的风险 - 随便说说),也不能使用允许私人成员的工具测试(例如 Typemock,它是付费产品)。对于这种情况,您可以完全不测试,或者偷工减料。我认为这是 OP 面临的情况。


撇开私有方法测试讨论...

请记住,您可以使用 反射 来访问和调用私有成员。

在我看来,将条件调试 放在 类本身是一个相当糟糕的主意 - 它会在类代码中添加 noise(例如,一些不相关的东西)。当然,它会在发布时消失,但你(可能还有其他程序员)将不得不在日常基础上处理它。

我意识到您的想法在纸上听起来可能不错 - 包含条件调试的简单测试。但实际上,测试很快就会使用额外变量(这些也必须放在类代码中),一些实用程序(额外引用,自定义类型), 测试框架(更多参考)等等。这一切都必须以某种方式连接到类代码。把所有这些放在一起,你很快就会得到一个无法维护的怪物

您确定要处理这个问题吗?特别是考虑到将简单的基于反射的实用程序放在一起可能并不难。

【讨论】:

  • +1 我认为在特殊或罕见情况下单元测试中使用的反射是可以接受的“较小的邪恶”。以全面的方式使用它来测试所有私有方法可能会导致麻烦。
  • 也就是说,我个人会尝试重构以提高可测试性。
  • 谢谢!使用反射正是我忘记的。
  • 我真的认为一个更好的选择是重构将私有方法提取到另一个类中并通过构造函数将其注入。通过反射测试私有方法是一种气味恕我直言。
  • 为了其他人看到这个问题,我只想附和同意上述观点。这种方法实际上并不是一个聪明的技巧,而是一种最后的应对机制。即便如此,当我输入此内容时,迅猛龙仍会抓着我的门。
【解决方案2】:

您所指的一切都可以通过两个概念来解决:Single Responsibility PrincipleDependency Injection。听起来你肯定需要简化你的课程。请注意,这并不意味着该类必须提供更少的价值,它只是意味着内部需要更简单,并且某些功能可能必须委托给其他人。

【讨论】:

  • +1 因为我完全同意依赖注入是解决这个问题的最佳答案。
  • 我希望是这样。但是这个类确实有一个单一的、不可分割的责任,并且它没有依赖注入。这是一个公认的特殊情况 - 这就是我正在探索特殊解决方案的原因。
  • @SeanU 在我的回答中,我讨论了依赖于私有方法本身的想法。我很想看看代码并知道为什么你不能通过测试公共成员来满足这个实现的原因。
【解决方案3】:

如果您需要独立于类的公共 API 测试此方法,那么听起来像是从类本身中删除的候选对象。

您可以说该类依赖私有方法(这可以证明需要将其与类公共 API 分开测试)。

如果通过测试 alone 类型的公共 API 无法满足此依赖关系,则让该类将此依赖关系委托给另一种类型。您可以在内部实例化此类型,也可以注入/解析此类型。

这种新类型可以然后拥有自己的单元测试,因为它的公共 API 将表达以前的私有方法。

【讨论】:

    猜你喜欢
    • 2010-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    • 2014-12-30
    • 1970-01-01
    相关资源
    最近更新 更多