我应该测试私有方法还是仅测试公共方法?
我已经阅读了有关如何测试私有方法的文章。我通常不测试它们,因为我一直认为仅测试将从对象外部调用的公共方法会更快。我们是否测试私有方法?我应该一直测试它们吗?
解决方案
我认为单元测试用于测试公共方法。公共方法使用私有方法,因此它们也间接受到测试。
如果我们不测试自己的私有方法,我们怎么知道它们不会中断?
我不对私有方法进行单元测试。私有方法是应该对类用户隐藏的实现细节。测试私有方法会破坏封装。
如果我发现私有方法庞大,复杂或者重要到足以需要自己的测试,就将其放在另一个类中并在其中公开(方法对象)。然后,我可以轻松地测试现在存在于其自己的类中的以前私有但现在公开的方法。
我认为最好只是测试对象的公共接口。从外部世界的角度来看,仅公共接口的行为很重要,这是单元测试应针对的目标。
一旦为对象编写了一些可靠的单元测试,我们就不必再回过头来更改那些测试,只是因为接口背后的实现发生了变化。在这种情况下,我们已经破坏了单元测试的一致性。
我不是该领域的专家,但是单元测试应该测试行为,而不是实现。专用方法严格是实现的一部分,因此不应进行IMHO测试。
显然,这取决于语言。过去使用c ++时,我已将测试类声明为朋友类。不幸的是,这确实需要生产代码了解测试类。
我们通过推论来测试私有方法,这意味着我们寻求的总类测试覆盖率至少为95%,但只有我们的测试调用到公共或者内部方法中。为了获得覆盖,我们需要根据可能发生的不同情况多次致电给公共/内部人员。这使我们的测试更加专注于要测试的代码的目的。
Trumpi对我们所链接帖子的回答是最好的。
我倾向于遵循戴夫·托马斯(Dave Thomas)和安迪·亨特(Andy Hunt)在他们的《实用单元测试》一书中的建议:
In general, you don't want to break any encapsulation for the sake of testing (or as Mom used to say, "don't expose your privates!"). Most of the time, you should be able to test a class by exercising its public methods. If there is significant functionality that is hidden behind private or protected access, that might be a warning sign that there's another class in there struggling to get out.
但是有时候我无法阻止自己测试私有方法,因为它使我感到放心,因为我正在构建一个完全健壮的程序。
如果私有方法未通过调用公共方法进行测试,那么它在做什么?
我说的是不受保护的私人或者朋友。
如果私有方法定义明确(即,它具有可测试的功能,并且不打算随时间变化),则可以。我会在有意义的地方测试所有可测试的东西。
例如,加密库可能掩盖了它使用一次仅加密8个字节的私有方法执行块加密的事实。我会写一个单元测试,即使它是隐藏的也不意味着要更改,并且如果它确实发生了损坏(例如,由于将来性能的提高),那么我想知道是私有函数损坏了,而不仅仅是一项公共职能中断了。
稍后可以加快调试速度。
-亚当
在执行项目中越来越多的最新质量检查建议之一时,我感到不得不测试私有功能:
No more than 10 in cyclomatic complexity per function.
现在,执行此策略的副作用是,我的许多大型公共职能被划分为许多更集中,名称更好的私有职能。
公共功能仍然存在(当然),但本质上被简化为称为所有这些私有"子功能"
这实际上很酷,因为调用栈现在更易于阅读(不是大型函数中的错误,而是子调用子函数中的一个错误,其名称与调用栈中的先前函数相同,可以帮助我理解'我怎么到达那里')
但是,现在似乎可以直接对那些私有功能进行单元测试,而将大型公共功能的测试留给某种需要解决方案的"集成"测试似乎更容易。
只是我的2美分。
测试的目的是什么?
到目前为止,大多数答案都说私有方法是实现细节,只要公共接口经过了良好的测试并且可以正常工作,它们就无关紧要(至少不应该如此)。如果我们唯一的测试目的是保证公共接口有效,那绝对是正确的。
就个人而言,我进行代码测试的主要用途是确保将来的代码更改不会引起问题,并在可能的情况下帮助我进行调试。我发现对私有方法的测试与对公共接口的测试一样彻底(如果不是,那么!)进一步实现了这一目的。
考虑:我们有一个公用方法A,该方法调用私有方法B。A和B都使用方法C。C被更改了(也许由我们,也许由供应商更改),导致A开始无法通过其测试。即使是私有的,也对B进行测试不是有用的,这样我们就知道问题出在A是使用C,B是使用C还是两者都存在?
在私有接口的测试范围不完整的情况下,测试私有方法还可以增加价值。虽然这是我们通常要避免的情况,但效率单元测试取决于发现错误的测试以及这些测试的相关开发和维护成本。在某些情况下,可能会判定100%测试覆盖率的好处不足以保证这些测试的成本,从而在公共界面的测试覆盖率上造成缺口。在这种情况下,对专用方法进行有针对性的测试可能是对代码库的非常有效的补充。
如果该方法足够重要/足够复杂,我通常会使其受到"保护"并进行测试。一些方法将被保留为私有方法,并作为公共/受保护方法的单元测试的一部分进行隐式测试。
如上所述,"如果不测试私有方法,我们怎么知道它们不会中断?"
这是一个主要问题。单元测试的重点之一就是要知道在什么地方,什么时间以及如何尽快破坏某些内容。因此减少了大量的开发和质量检查工作。如果所有测试都是公开的,那么我们就不会对课程内部有诚实的报道和描述。
我发现最好的方法之一就是将测试引用添加到项目中,然后将测试放入与私有方法平行的类中。放入适当的构建逻辑,以使测试不会构建到最终项目中。
这样,我们便具有测试这些方法的所有好处,并且可以在数秒而不是数分钟或者数小时内发现问题。
综上所述,是的,对私有方法进行单元测试。
如果我们正在开发测试驱动(TDD),则将测试私有方法。