我应该testing私有方法还是只testing公有方法?

我已经阅读这篇文章如何testing私人方法。 我通常不会testing它们,因为我一直认为只testing将从对象之外调用的公共方法会更快。 你testing私有方法吗? 我应该经常testing它们吗?

我不会unit testing私人方法。 私有方法是应该隐藏给类的用户的实现细节。 testing私有方法破坏封装。

如果我发现私有方法是巨大的,复杂的或者足够重要的以便需要它自己的testing,我就把它放在另一个类中并在那里公开( 方法对象 )。 然后,我可以很容易地testing现在生活在自己的课堂上以前私人但现在公开的方法。

testing的目的是什么?

到目前为止,大多数答案都是说私有方法是实现细节,只要公共接口经过良好testing和工作,就不会(或者至less不应该)重要。 如果您唯一的testing目的是保证公共接口正常工作,那么这是绝对正确的。

就我个人而言,我主要用于代码testing是为了确保将来的代码更改不会引起问题,并且如果他们这样做会帮助我的debugging工作。 我发现,像公共接口一样彻底地testing私有方法(如果不是更多的话),就会促进这个目的。

考虑:你有公共方法A,它调用私有方法B.A和B都使用方法C。C被改变(也许由你,也许由供应商),导致A开始失败它的testing。 对B进行testing也是有用的,尽pipe它是私密的,所以你知道问题出在A的使用C,B的使用C还是两者上?

在公共接口的testing覆盖率不完整的情况下,testing私有方法也会增加价值。 虽然这是我们通常希望避免的情况,但效率unit testing依赖于发现错误的testing以及这些testing的相关开发和维护成本。 在某些情况下,100%testing覆盖率的好处可能被认为不足以保证这些testing的成本,从而在公共接口的testing覆盖率上产生差距。 在这种情况下,针对私有方法的有针对性的testing可能是对代码库的有效补充。

我倾向于遵循Dave Thomas和Andy Hunt在“ 语用unit testing”一书中的build议:

一般来说,你不想为了testing而打破任何封装(或者像妈妈曾经说过的,“不要暴露你的私生子!”)。 大多数时候,你应该能够通过行使公共方法来testing一个class级。 如果隐藏在隐私或受保护访问后面的重要function可能是一个警告信号,那里面还有另一个class正在挣扎着走出去。

但是有时我无法阻止自己testing私有方法,因为它给了我一种安全感,我正在构build一个完全健壮的程序。

我有种感觉不得不testing私人function,因为我正在按照我们最近的QAbuild议在我们的项目中进行越来越多的testing:

每个function的复杂度不超过10个。

现在执行这个政策的副作用是,我的很多公共职能被分成了许多更有针对性,更好地命名的私人职能。
公共职能仍然存在(当然),但基本上被简化为称为所有这些私人的“子function”

这实际上是很酷的,因为callstack现在更容易阅读(而不是一个大函数中的bug,我在一个子函数中有一个错误,在调用堆栈中有前面的函数的名字来帮助我理解'我怎么到了')

然而,直接对这些私有函数进行unit testing现在看起来更容易,并且将大型公共函数的testing留在需要解决场景的某种“集成”testing中。

只是我2美分。

是的,我testing私有函数,因为虽然它们已经通过公共方法进行了testing,但是在TDD(testing驱动devise)中testing应用程序的最小部分是很好的。 但是当你在你的testing单元课上时,私人function是不可访问的。 以下是我们testing我们私有方法的方法。

为什么我们有私人的方法?

私有函数主要存在于我们的类中,因为我们想要在我们的公共方法中创build可读代码。 我们不希望这个类的用户直接调用这些方法,而是通过我们的公共方法。 而且,我们不希望改变他们的行为(在受保护的情况下),因此它是一个私人的。

当我们编码时,我们使用testing驱动devise(TDD)。 这意味着有时我们偶然会发现一些私密的function,并且想要testing。 私人函数不能在phpUnit中testing,因为我们无法在Test类中访问它们(它们是私有的)。

我们认为这里有3个解决scheme:

你可以通过你的公共方法来testing你的私人

优点

  • 简单的unit testing(不需要“黑客”)

缺点

  • 程序员需要了解公共方法,而他只想testing私有方法
  • 您没有testing应用程序的最小可testing部分

2.如果私人是如此重要,那么为它创build一个新的单独的类也许是一种代码

优点

  • 你可以把它重构成一个新的类,因为如果它是重要的,其他类也可能需要它
  • 可testing单元现在是一个公共方法,可以testing

缺点

  • 你不想创build一个类,如果不需要的话,只能用于方法来自的类
  • 潜在的性能损失是由于额外的开销

3.将访问修饰符更改为(final)protected

优点

  • 您正在testing应用程序的最小可测部分。 当使用final保护时,函数不会被覆盖(就像私人)
  • 没有性能损失
  • 没有额外的开销

缺点

  • 你正在改变私人访问受保护的,这意味着它的孩子可以访问
  • 你的testing课还需要一个Mock类来使用它

 class Detective { public function investigate() {} private function sleepWithSuspect($suspect) {} } Altered version: class Detective { public function investigate() {} final protected function sleepWithSuspect($suspect) {} } In Test class: class Mock_Detective extends Detective { public test_sleepWithSuspect($suspect) { //this is now accessible, but still not overridable! $this->sleepWithSuspect($suspect); } } 

所以我们的testing单元现在可以调用test_sleepWithSuspect来testing我们以前的私有函数。

我认为最好只testing一个对象的公共接口。 从外部的angular度来看,只有公共接口的行为才是重要的,这就是你的unit testing应该针对的东西。

一旦为某个对象编写了一些可靠的unit testing,就不必因为接口后面的实现发生变化而不得不返回并更改这些testing。 在这种情况下,你破坏了你的unit testing的一致性。

如果私有方法定义得很好(即它有一个可testing的function,并且不会随着时间而改变),那么是的。 我testing一切可以testing的地方。

例如,一个encryption库可能会隐藏一个事实,即它使用一次只能encryption8个字节的私有方法执行块encryption。 我会为此编写一个unit testing – 即使它是隐藏的,并不意味着改变,并且如果它确实中断(例如由于将来的性能增强),那么我想知道是私有函数崩溃了,而不是公共职能之一爆发了。

它稍后加速debugging。

-亚当

如果你的私有方法没有通过调用你的公共方法来testing,那么它在做什么? 我说私人没有保护或朋友。

如果您正在开发testing驱动(TDD),您将testing您的私有方法。

我们通过推理来testing私人方法,我的意思是我们要求至less95%的总体类testing覆盖率,但是只有我们的testing可以用公共或内部的方法进行testing。 为了获得覆盖范围,我们需要根据可能发生的不同情况对公共/内部进行多次调用。 这使我们的testing更加关心他们正在testing的代码的目的。

Trumpi对你链接的post的回答是最好的。

我不是这个领域的专家,但是unit testing应该testing行为,而不是执行。 私有方法是严格执行的一部分,所以恕我直言,不应该被testing。

unit testing我相信是testing公共方法。 你的公共方法使用你的私有方法,间接地他们也被testing。

我已经在这个问题上徘徊了一段时间,特别是在TDD上试试我的手。

我遇到过两篇文章,我认为在TDD的情况下,这个问题已经足够彻底。

  1. testing私有方法,TDD和testing驱动的重构
  2. testing驱动的开发不是testing

综上所述:

  • 当使用testing驱动的开发(devise)技术时,私有方法只能在已经工作和testing的代码的重新分解过程中出现。

  • 根据这个过程的本质,从经过全面testing的function中提取的简单实现function的任何一点都将被自我testing(即间接testing覆盖)。

对我来说,似乎很清楚,在编码的开始部分,大多数方法将是更高层次的function,因为它们封装/描述了devise。

因此,这些方法将是公开的,testing它们会很容易。

一旦一切运转良好,私人方法将会迟到,为了可读性清洁性 ,我们正在考虑因素。

如上所述,“如果你不testing你的私人方法,你怎么知道他们不会打破?

这是一个重大问题。 unit testing的重点之一是要知道什么地方,什么时候,以及如何破坏。 从而减less了大量的开发和QA工作。 如果所有被testing的都是公众,那么你就没有诚实的报道和划分课堂内部。

我发现最好的方法之一就是简单地将testing引用添加到项目中,并将testing放在一个与私有方法并行的类中。 放入适当的构build逻辑,以便testing不会构build到最终项目中。

那么你就拥有testing这些方法的所有好处,你可以在几秒钟内发现问题,而不是几分钟或几小时。

所以总之,是的,unit testing你的私有方法。

如果你不testing你的私人方法,你怎么知道他们不会打破?

你不应该 。 如果你的私有方法有足够的复杂性,必须testing,你应该把它们放在另一个类。 保持高度凝聚力 ,一个class级应该只有一个目的。 类的公共接口应该是足够的。

这显然是语言的依赖。 在过去用c ++,我已经宣布testing类是一个朋友类。 不幸的是,这确实需要您的生产代码来了解testing类。

我理解私有方法被视为实现细节的观点,然后不必进行testing。 如果我们不得不在对象之外开发,我会坚持这个规则。 但是,我们是不是也只是在对象之外开发的受限制的开发者,只是调用他们的公共方法呢? 或者我们是否也在开发这个对象? 由于我们不一定要在对象之外编程,我们可能不得不将这些私有方法称为正在开发的新的公共方法。 知道私人方法抵御一切困难不是很好吗?

我知道有些人可以回答,如果我们正在开发另一种公开的方法,那么这个应该被testing,就是这样(私人方法可以继续生活,没有testing)。 但是对于对象的任何公共方法也是如此:在开发Web应用程序时,对象的所有公共方法都从控制器方法中调用,因此可以被视为控制器的实现细节。

那么为什么我们要testing单元呢? 因为这确实很困难,不能说我们不能确定我们正在用适当的input来testing控制器的方法,这会触发底层代码的所有分支。 换句话说,我们在堆栈中越高,testing所有行为就越困难。 私人方法也是如此。

对于我来说,私人和公共方法之间的边界在testing时是一个心理标准。 更重要的标准是:

  • 是不是从不同的地方不止一次的方法?
  • 是足够复杂的方法需要testing?

如果我发现私有方法是巨大的,复杂的或者足够重要的以便需要它自己的testing,我就把它放在另一个类中并在那里公开(方法对象)。 然后,我可以轻松地testing以前私人的,但现在公开的方法,现在生活在自己的阶级。

绝对没错。 这是unit testing的重点,你testing单位。 私人方法是一个单位。 没有testing私有方法TDD(testing驱动开发)将是不可能的,

如果我们testing以确保逻辑的正确性,并且私有方法正在携带逻辑,那么我们应该testing它。 不是吗? 那么,为什么我们要跳过呢?

基于方法的可见性编写testing是完全不相关的想法。

如果方法足够重要/足够复杂,我通常会使其“受保护”并进行testing。 一些方法将被隐藏并作为公共/受保护方法的unit testing的一部分进行隐式testing。

我看到很多人都在思考:在公共层面进行testing。 但这不是我们的QA团队做的吗? 他们testinginput和预期的输出。 如果作为开发人员,我们只testing公共方法,那么我们只是重做QA的工作,而不是通过“unit testing”增加任何价值。

答案是“我应该testing私有方法吗?” 是“…….有时”。 通常你应该在你的类的接口上进行testing。

  • 其中一个原因是因为您不需要双重覆盖function。
  • 另一个原因是,如果你改变私有方法,你将不得不为他们更新每个testing,即使你的对象的接口根本没有改变。

这里是一个例子:

 class Thing def some_string one + two end private def one 'aaaa' end def two 'bbbb' end end class RefactoredThing def some_string one + one_a + two + two_b end private def one 'aa' end def one_a 'aa' end def two 'bb' end def two_b 'bb' end end 

RefactoredThing你现在有5个testing,其中2个你必须更新重构,但是你的对象的function并没有改变。 所以让我们说,事情比这更复杂,你有一些方法来定义输出的顺序,如:

 def some_string_positioner if some case elsif other case elsif other case elsif other case else one more case end end 

这不应该由外部用户来运行,但是你的封装类可能会沉重地通过它重复运行那么多的逻辑。 在这种情况下,也许你宁愿将这个提取到一个单独的类中,给这个类一个接口并对它进行testing。

最后,让我们说,你的主要对象是超重的,这个方法是非常小的,你真的需要确保输出是正确的。 你在想,“我必须testing这个私人的方法!”。 你是否也许可以通过把一些繁重的工作作为一个初始化parameter passing给你的对象? 然后,你可以传递一些更轻的东西,并对此进行testing。

不,你不应该testing私有方法为什么? 而且像Mockito这样的stream行嘲笑框架不提供对testing私有方法的支持。