1

我从POODR等书籍中看到的关于 TDD 的一般建议是不要测试私有方法。这个想法是调用私有方法的公共方法将被测试,并且应该足以验证私有方法。

这是有道理的,但是私有方法有几个“层”深的情况呢?这是我的意思的一个人为的例子:

public

# test this method
def foo
  private1
end

private

def private1
  private2
end

def private2
  private3
end

def private3
  # does stuff
end

我没有要分享的真实示例,但是在这种情况下,仅测试公共方法是否仍然足够好foo?或者这样构造的代码是否指向了一个可能更深层次的问题?

4

5 回答 5

3

这背后的想法是类的内部是该类的实现细节。

您设计的示例仅将 foo 的输出公开给用户。所以这是你的测试必须确保不会改变的唯一事情。

如果你用 foo 之类的 10 个方法干掉整个类,只在内部使用一种方法,你不会希望看到任何测试中断,因为你更改为 private。只要公共接口仍然有效,就不需要测试内部。

这背后的原理是封装。你不在乎你的班级在幕后做了什么——你只关心它可以在量子计算机上运行并将它的数据流发送给月球上的人进行计算——只要输出是正确的你的用户将看到正确和预期的结果。

任何测试私有的尝试都只会导致一旦您更改这些方法,测试就会中断。在很多情况下这很好,但是过度测试会让你花费更多的时间来修复损坏的测试而不是提高效率,所以这条规则主要是为了给你一些回旋余地。

当然,这个建议总是取决于:如果你觉得这个方法很重要,你可能想为它编写测试。但无论如何,这些测试大多是您已经为公共方法进行的测试的重复。

于 2013-10-07T10:24:51.757 回答
1

我仍然只测试#foo,因为它是其他对象所依赖的唯一方法。如果您的测试“证明” foo 做了它应该做的事情,那么调用多少私有方法来完成这一点并不重要。

您可能会喜欢 Sandy Metz 的演讲,该演讲进一步说明了测试技术: http ://www.youtube.com/watch?v=URSWYvyc42M

但我明白你的担忧。如果您对您的私有方法之一感到不安全,可以编写一些测试以对该方法更有信心,但不要浪费太多时间来维护这些测试。

假设您更改了一些实现细节,现在#private2 的测试失败,但#foo 的测试仍然是绿色的,我不会花太多时间来修复#private2。(换句话说,删除#private2 的测试)

于 2013-10-07T10:26:24.667 回答
0

我认为测试函数 foo 足以测试其他私有函数。我没有发现深层函数调用有任何问题。Foo 函数作为一个单元应该适用于所有断言。

于 2013-10-07T10:24:16.960 回答
0

我并不总是照本宣科。有时需求/要求也决定了您的方法。

就在几天前,我遇到了这种情况。尽管我正在编写Java代码,并且我的答案基于 Java,但无论您考虑哪种编程语言,它都可能仍然相关。

在尝试为现有的(旧的)巨大类(代码覆盖率 <40%)实现良好的代码覆盖率时,我不得不编写几个测试用例,因此注意到了一些事情:

1)很少有本应是“私有”的方法被赋予“默认”(包级别)访问修饰符,以便可以对其进行测试。(使用JUnit 4)
---结果证明这些方法是错误的方法'应该是“私人的”。我不得不将它们更改为“私有”并修改测试用例。

2)为了增加代码覆盖率,我不得不调用公共方法并测试深层的“私有”方法。为此,我必须阅读/理解整个庞大的课程。(这个类只有 2 个公共方法和大约 15-20 个私有方法,很少有 4-5 个“级别”深度的方法调用)。
---正如您可能已经发现的那样,这太复杂了。毫无疑问,这些私有方法中的很多都变得难以测试:(

最后,我厌倦了阅读所有这些旧代码,并继续单独测试每个方法(使用“反射”测试私有方法)。在一个古老而庞大的系统中,这很有意义。
我的每个单元测试都确保它只测试一种方法的正确性。
如果任何方法未能达到预期效果,那么通过这种方式修复任何错误非常容易。

当然,这里可以争论说应该尊重封装,我的测试用例应该只调用公共方法。
但是,当有一个深入 5 层的私有方法没有做预期的事情时怎么办?您如何在旧代码中找到此错误!!!您不希望每种方法都经过测试吗?
在这种情况下,类没有机会改变其业务逻辑。因此,不存在维护测试类的问题。
尽管这个类是众多重构的绝佳候选者,但当您接近代码冻结时,您不会想接受它!:)

简而言之,答案可能因情况而异。根据您的需求/要求,您/您的团队将成为这方面的最佳决策者,因为您将是最了解您的系统的人......希望 ;)

于 2013-10-14T15:19:41.523 回答
0

测试公共接口才有意义,因为您希望确保与代码的外部交互是安全的并且按预期工作,同时您希望保持合理的灵活性来更改实现而不更改测试。

如果您认为私有方法中包含的概念足够复杂或有趣,您可能希望将其转换为单独的类,创建新的公共接口并为它们编写测试。有很多建议可以帮助您确定何时清理类,例如SOLID原则

永远不要考虑编写测试或类似的代码,您不打算维护。

于 2013-10-07T13:13:17.210 回答