5

使用私有方法通过将一些决策点重构为单独的方法来降低 CC 会降低实际方法的 CC 并易于阅读,但不会减少在测试中获得完整分支覆盖的工作量。

这合理吗?你有什么现场经验?

4

6 回答 6

3

好吧,如果您仍然感兴趣,那么我写的这篇文章是关于Cyclomatic Complexity

以不同的方法削减你的代码不会降低复杂性,但只会有助于在本地建立一个更好的组织。减少CC的唯一真正方法就是重构!

如果您只提取方法,您将需要相同数量的测试。看看你的数据结构可能对你没有帮助吗?如果有感觉,也可以考虑削减几个班级。

于 2012-05-04T13:24:14.597 回答
2

有时,使您的应用程序代码不那么复杂且更具可读性会导致您的测试代码变得更复杂且可读性更低。但是,这不是不进行重构的理由。生产代码的可读性比您的测试更重要。

如果您将某些方法设为私有以降低 CC 并提高可读性,您可以使用像 Mockito 这样的框架来仍然能够自己测试私有方法。

于 2011-04-18T15:45:59.140 回答
2

以我的经验,这是一种非常常见的情况——让你的生产代码做正确的事情使得测试变得更加困难。
其他示例包括将实现细节隐藏在接口后面,永远不会到达外部调用者的 ORM 实体,使某些功能仅通过 Web 服务调用可用。 ..并且通常在生产中拥有您期望的 API 会经常限制测试。

是的,在经过大量重构之后,要恢复覆盖范围是一件痛苦的事情。有时,当难以测试的功能没有正确测试时,这会导致整体进度逆转。所以我一般同意 Fortega,除了最后一句话。不要让你的测试腐烂。他们会在你最不想要的时候回来。

于 2011-04-18T16:08:08.210 回答
2

我真的不明白你的问题。显然,将大方法中的逻辑和决策点重构为私有方法将降低大方法的圈复杂度。这就是提取方法的重点——它使大方法更短更简单,因此希望更容易理解和改变。

这不是作弊,它只是让你的程序结构变得明确。

但不会减少在测试中获得完整分支覆盖的努力。

这对我来说似乎是不合理的。为什么要分解私有方法使覆盖测试更容易?我从未见过有人这么说。你是不是误会了什么?

于 2011-04-18T17:19:49.373 回答
1

你永远不应该重构你的代码,因为你认为改进一个指标喷涌而出的数字对你的代码有好处。与其追求数字和花哨的报告(不幸的是我已经看到这样做了),不如着眼于理解指标以及首先使用它的原因。

圈复杂度是一种简单的数学度量,它仅说明如果所有分支都被导航,您的代码可以执行多少不同的路径。所以是的,高圈复杂度确实表明您的测试可能会变得更加复杂。但有时根本没有更简单的方法来编写具有高 CC 和大量测试的代码。你只需要知道什么时候这是一个公平的做法,什么时候你的设计有问题。在旁注中,通过将代码拆分为方法来减少 CC 并不能简化测试任务,因为无论哪种方式都必须覆盖代码。这只是看起来“更漂亮”的数字。

考虑以下内容:您的任务是设计对按键做出反应的代码,并根据按下的键执行某些任务。该设备仅具有固定数量的按钮,这意味着软件首先需要详尽无遗并且不需要可扩展(采用该命令模式)。

您可以编写一个switch易于阅读的简单语句,每次按下按钮触发一个方法。这将是快速有效地解决此任务的好方法。但是获得按键的方法的CC将是可怕的。你应该拆分代码吗?为什么?我的意思是它是可读的,完美地服务于它的目的,无论你做什么,你的测试仍然需要考虑每个按钮的按下。所以除了减少这个数字之外,重构没有任何好处。

我的建议是了解什么时候圈复杂度是一个有意义的指标,什么时候不是。此外,请尝试 Micheal博客文章中的一些重构建议。它有一些可靠的建议。

于 2014-06-04T12:34:47.340 回答
1

想象一下,您正在过一座重量限制为 10,000 磅的桥梁,而您正在驾驶一辆载有 15,000 磅货物的卡车。为了适应限制,您将货物分成三个拖车,每个拖车重 5,000 磅,然后将它们拉到卡车后面。从技术上讲,它减轻了卡车的重量,但桥上的压力保持不变。

将代码从一个大方法移动到较小的、未经测试的私有方法中是类似的。它使原始方法看起来不那么复杂,并且有一些好处。但是,如果它真的以一种有意义的方式降低了原始方法的复杂性,那么该方法将变得更容易测试。它没有。

对原始方法的任何测试仍必须测试它调用的私有方法中的所有逻辑,就像这些新方法中的所有代码仍在原始方法中一样。如果我们之前无法测试(或者非常困难),那么我们仍然会遇到完全相同的问题。

如果我们将代码提取到私有方法中作为垫脚石,以将它们与原始方法隔离,甚至可能与原始类隔离,这会有所帮助。我们可以将这些方法移动到新类中,然后将这些类注入到原始类中。或者根据语言,也许我们可以注入方法。

完成后我们可以

  • 对注入的依赖项使用模拟测试原始方法。模拟没有复杂性。它每次都做它被告知的事情。现在对原始方法的测试不包括那些私有方法中的所有代码。我们只需要验证它是否与这些依赖项按预期交互。
  • 测试新的类和方法。它们也更小更简单,这使得它们更容易测试。
于 2021-09-10T18:18:00.197 回答