私人/受保护方法是否应该进行unit testing?

在TDD开发中,你通常做的第一件事是创build你的接口,然后开始编写你的unit testing对接口。 当你通过TDD过程时,你最终会创build一个实现接口的类,然后在某个时候你的unit testing会通过。

现在我的问题是关于私有和受保护的方法,我可能必须在我的类中写入以支持接口公开的方法/属性:

  • class上的私人教学方法应该有自己的unit testing吗?

  • class上的保护方法是否应该有自己的unit testing?

我的想法:

  • 特别是因为我正在编写接口,所以我不应该担心保护/私有方法,因为它们是黑盒子。

  • 因为我正在使用接口,所以我正在编写unit testing来validation所定义的合同是否由实现接口的不同类正确实现,所以我不必担心私有/受保护的方法,应该通过调用方法/属性由接口定义。

  • 如果我的代码覆盖不显示受保护/私有方法正在被打,那么我没有正确的unit testing,或者我没有使用的代码,应该被删除。

不,我不想testing私有或受保护的方法。 类的私有和被保护的方法不是公共接口的一部分,所以他们不公开公共行为。 通常,这些方法是通过在将testing变成绿色后应用的重构创build的。

所以这些私有方法由testing来隐式testing,这些testing声明了公共接口的行为。

从更哲学的angular度来看,请记住,你正在testing行为,而不是方法。 因此,如果您想到被testing类可以执行的一系列事情,只要您可以testing并声明该类的行为如预期那样,是否存在由类内部使用的私有(和受保护)方法来实现这种行为是无关紧要的。 这些方法是公共行为的实现细节。

你写了:

在TDD开发中,你通常做的第一件事是创build你的接口,然后开始编写你的unit testing对接口。 当你通过TDD过程时,你最终会创build一个实现接口的类,然后在某个时候unit testing会通过。

请让我用BDD语言来重述一下:

在描述为什么一个类是有价值的以及它如何performance的时候,你通常要做的第一件事就是创build一个如何使用这个类的例子,通常通过它的接口*。 当你添加所需的行为,你最终创build一个类,它提供了这个价值,然后在某个时候你的例子工作。

*可能是一个实际的Interface或简单的类的可访问的API,例如:Ruby没有接口。

这就是为什么你不testing私有方法的原因 – 因为testing是如何使用这个类的一个例子,而你实际上不能使用它们。 如果你想把私有方法的责任委托给一个协作类,那么你可以做的事情,然后模拟/存根帮手。

用受保护的方法,你说的是扩展你的类的类应该有一些特定的行为并提供一些价值。 然后,您可以使用类的扩展来演示这种行为。 例如,如果您正在编写有序的集合类,则可能需要certificate具有相同内容的两个扩展展示了相等性。

希望这可以帮助!

我不同意大多数的海报。

最重要的规则是:关于公共/保护/私人的工作代码公共理论规则。

你的代码应该经过彻底的testing。 如果你能通过写公共方法的testing来达到目的,那么这个方法就足以行使受保护的/私有的方法,这太好了。

如果你不能,那么要么重构,要么可以弯曲受保护的/私有的规则。

有一个关于给孩子做testing的心理学家的好故事。 他给每个小孩两块木板,每根木头都有一根绳子,要求他们尽可能快地穿过一个房间,不要双脚碰到地板。 所有的孩子们都喜欢用滑雪板,每块板上有一只脚,用绳子抓住它们,滑过地板。 然后,他给了他们相同的任务,但只使用一个董事会。 他们在地板上转动/“走过”,单板两端各有一只脚 – 而且他们更快!

只是因为Java(或其他语言)具有一个特性(private / protected / public)并不一定意味着你正在编写更好的代码,因为你使用它!

现在,总会有办法来优化/最小化这种冲突。 在大多数语言中,你可以使一个方法受保护(而不是public),并把testing类放在同一个包(或其他)中,并且该方法可用于testing。 如其他海报所描述的,注释可以提供帮助。 你可以使用reflection来获取私有方法(yuck)。

上下文也很重要。 如果你正在编写一个供外部人使用的API,公共/私人更重要。 如果这是一个内部项目 – 谁真的关心?

但是在一天结束的时候,考虑一下由于缺lesstesting造成了多less错误。 然后比较“过度可见”方法造成了多less错误。 这个答案应该推动你的决定。

当你为你的类编写unit testing的时候,你不必在乎这个类的function是直接在公共接口的方法中实现还是用一系列的私有方法来实现。 所以是的,你应该testing你的私有方法,但你不应该直接从你的testing代码中调用它们(直接testing私有方法将你的实现紧紧地耦合到你的testing中,并且使得重构变得不必要的困难)。

受保护的方法在你的class级和未来的孩子之间形成了一个不同的契约,所以你应该真的把它testing到与你的公共接口类似的程度,以确保合同的定义和行使。

没有! 只testing接口。

TDD最大的好处之一就是确保无论您如何select实现私有方法,接口都能正常工作。

完成别人上面所说的,我会说受保护的方法是某种接口的一部分:它只是接触inheritance而不是组合的接口,这是每个人在考虑接口时都会考虑的问题。

将一个方法标记为受保护而不是私有意味着它被第三方代码所使用,所以需要定义和testing某种契约,就像用公共方法定义的普通接口一样,这些接口对于inheritance和构造都是开放的。

不,你不应该testing私人方法(如果没有使用像reflection这样可怕的东西,你会怎么做)。 使用受保护的方法,在C#中稍微不太明显,您可以使内部受保护,我认为可以这样做来testing通过模板模式方法实现其所有function的派生类。

但是,一般来说,如果您认为您的公共方法做得太多,那么现在是时候将您的类重构为更多的primefaces类,然后testing这些类。

编写testing有两个原因:

  1. 声明预期的行为
  2. 防止行为退化

承担(1)断言预期的行为:

当你断言预期的行为时,你想确保代码的工作,你认为应该。 这实际上是一种自动化的方式来进行日常手动validation,任何开发人员在执行任何types的代码时都会执行:

  • 我刚刚写了什么作品?
  • 这个循环是否真的结束了?
  • 它是按照我认为的顺序循环吗?
  • 这将工作为空input?

这些都是我们都在脑海中回答的问题,通常我们也会试着在头脑中执行代码,确保它看起来像是有效的。 对于这些情况,让计算机以明确的方式回答它们通常是有用的。 所以我们编写一个声明它的unit testing。 这使我们对代码充满信心,帮助我们尽早发现缺陷,甚至可以帮助实际执行代码。

无论你觉得有必要,这是一个好主意。 任何有点难以理解的代码,或者是不重要的。 即使是微不足道的代码也可以从中受益。 这完全取决于你自己的信心。 多久去做一次,走多远取决于你自己的满意度。 当你可以自信地回答是的时候停下来:你确定这有效吗?

对于这种testing,你不关心可视性,界面或任何这些,你只关心有工作的代码。 所以是的,如果你觉得他们需要testing你的答案是肯定的,你会testing私有和受保护的方法。

(2)防止行为退化:

一旦你有了工作代码,你需要有一个机制来保护这些代码免受未来的破坏。 如果没有人再次碰到你的源代码和你的configuration,你就不需要这个了,但是在大多数情况下,你或者其他人会触摸你的软件的源代码和configuration。 这个内部摆弄很可能会破坏你的工作代码。

大多数语言已经存在机制来防止这种损害。 可见性function是一种机制。 私有方法是孤立的,隐藏的。 封装是另一种机制,在这种机制中,你划分了一些东西,所以改变其他的隔间不会影响其他的东西。

这一般的机制被称为:编码到边界。 通过在代码的各个部分之间创build边界,可以保护边界内的所有内容。 边界成为互动的点,以及事物相互作用的契约。

这意味着,通过打破界面或打破预期的行为,改变边界将会破坏并可能破坏依赖它的其他边界。 这就是为什么进行unit testing是一个好主意,这个unit testing是针对这些边界的,并声明它们在语义和行为上都不会改变。

这是你典型的unit testing,大家提到TDD或BDD时最讲的。 重点是加强边界,保护他们免受改变。 你不想为此testing私有方法,因为私有方法不是一个边界。 受保护的方法是一个有限的边界,我会保护它们。 他们没有暴露于世界,但仍然暴露于其他舱室或“单位”。

这个怎么办?

正如我们所看到的,unit testing公共方法和受保护的方法是有原因的,因为断言我们的接口不会改变。 testing私有方法也有很好的理由来证实我们的实现。 那么我们应该unit testing一下吗?

是和不

首先 :testing所有的方法,你觉得你需要一个明确的certificate,它在大多数情况下工作,以便能够确信你的代码工作,无论是可见性。 然后,禁用这些testing。 他们做了那里工作。

最后 :为你的边界写testing。 对您的系统的其他部门使用的每个点进行unit testing。 确保这个testing声明了语义契约,方法名称,参数数量等等。还要确保testing声明单元的可用行为。 你的testing应该演示如何使用该单元,以及该单元可以做什么。 保持启用这些testing,以便它们在每次代码推送时运行。

注意:禁用第一组testing的原因是允许重构工作发生。 主动testing是代码耦合。 它可以防止未来对其正在testing的代码进行修改。 你只需要这个接口和交互契约。

我同意@ kwbeam关于不testing私有方法的答案。 然而,我想强调一个重要的点 – 受保护的方法是类导出的API的一部分,因此必须进行testing。

受保护的方法可能无法公开访问,但您肯定正在为子类提供一种使用/覆盖它们的方法。 class外有东西可以访问它们,因此你需要确保那些受保护的成员以预期的方式行事。 所以不要testing私有方法,而是testing公共和受保护的方法。

如果你相信你有一个包含关键逻辑的私有方法,我会尝试将它提取到一个单独的对象中,隔离它并提供一种方法来testing它的行为。

希望它有帮助!

我同意其他人的观点:你的问题的答案是“不”。

事实上,对于您的方法和想法,尤其是代码覆盖面,您完全正确。

我还要补充一点,这个问题(和答案“否”)也适用于你可能会介绍给类的公共方法。

  • 如果您添加方法(公共/受保护或私有),因为他们通过了失败的testing,那么您已经或多或less地达到了TDD的目标。
  • 如果您添加方法(公共/保护或私有),因为您决定违反TDD,那么您的代码覆盖范围应该能够抓住这些方法,并且您应该能够改进您的过程。

此外,对于C ++(我只想C ++)我只使用私有方法实现接口,以指示该类只能通过它实现的接口使用。 它阻止我错误地调用从我的testing中添加到我的实现中的新方法

如果你的代码覆盖率很高(我build议你应该),你应该testing你的所有方法,不pipe它们是私有还是保护。

保护是一个不同的讨论点,但总的来说,它不应该在那里。 要么破坏已部署代码的封装,要么迫使你从该类inheritance,只是为了unit testing,甚至有时候你不需要inheritance。

只是隐藏一个方法给客户(使私人)不赋予它有特权不被审计。 因此,他们可以通过前面提到的公共方法来testing。