我已经阅读了这篇关于如何测试私有方法的文章。我通常不测试它们,因为我总是认为只测试将从对象外部调用的公共方法更快。你测试私有方法吗?我应该一直测试它们吗?


当前回答

我倾向于遵循Dave Thomas和Andy Hunt在他们的书《实用单元测试》中的建议:

一般来说,为了不破坏任何封装 测试(或者就像妈妈常说的,“不要暴露你的私处!”)。大多数 此时,您应该能够通过执行类的 公共方法。如果隐藏了重要的功能 在私人或受保护访问的背后,这可能是一个警告信号 还有一群人在里面挣扎着想出来。

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

其他回答

它不仅涉及公共或私有方法或函数,还涉及实现细节。私有函数只是实现细节的一个方面。

毕竟,单元测试是一种白盒测试方法。例如,无论谁使用覆盖率分析来识别到目前为止在测试中被忽略的代码部分,都将进入实现细节。

A)是的,你应该测试实现细节:

考虑一个排序函数,如果有多达10个元素,则出于性能考虑使用BubbleSort的私有实现,如果有超过10个元素,则使用不同排序方法(例如堆排序)的私有实现。公共API是排序函数的API。但是,您的测试套件更好地利用了实际上使用了两种排序算法的知识。

在本例中,当然可以在公共API上执行测试。然而,这需要有大量的测试用例来执行具有10个以上元素的排序函数,以便对堆排序算法进行充分的测试。这种测试用例的单独存在表明测试套件连接到功能的实现细节。

如果排序函数的实现细节发生了变化,可能是两种排序算法之间的限制发生了变化,或者堆排序被归并排序取代了,或者其他:现有的测试将继续工作。然而,它们的价值是值得怀疑的,它们可能需要重新工作,以更好地测试更改后的排序函数。换句话说,尽管测试是在公共API上进行的,但仍然需要进行维护工作。

B)如何测试实现细节

许多人认为不应该测试私有函数或实现细节的一个原因是,实现细节更有可能改变。这种更高的更改可能性至少是将实现细节隐藏在接口后面的原因之一。

现在,假设接口背后的实现包含更大的私有部分,可以选择在内部接口上进行单独的测试。有些人认为,这些部分不应该在私人的时候进行测试,它们应该变成公共的东西。一旦公开,对代码进行单元测试就可以了。

这很有趣:虽然接口是内部的,但它很可能会改变,这是一个实现细节。使用相同的接口,将其公开可以进行一些神奇的转换,即将其转换为不太可能更改的接口。显然,这种论证有一些缺陷。

但是,这背后仍然有一些事实:在测试实现细节时,特别是使用内部接口时,应该尽量使用可能保持稳定的接口。然而,某些接口是否可能是稳定的,不能简单地根据它是公共的还是私有的来确定。在我工作过一段时间的项目中,公共接口也经常发生变化,而许多私有接口多年未动。

不过,“先从正门走”是一个很好的经验法则(见http://xunitpatterns.com/Principles%20of%20Test%20Automation.html)。但请记住,这是“前门优先”,而不是“只有前门”。

C)总结

还要测试实现细节。更喜欢在稳定接口(公共或私有)上进行测试。如果实现细节发生变化,也需要修改对公共API的测试。把私人的东西变成公共的东西并不能神奇地改变它的稳定性。

我认为单元测试是用来测试公共方法的。您的公共方法使用您的私有方法,因此它们也间接地接受测试。

测试的目的是什么?

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

就我个人而言,我对代码测试的主要用途是确保将来的代码更改不会导致问题,并且在出现问题时帮助我进行调试。我发现对私有方法的测试就像对公共接口的测试一样彻底(如果不是更彻底的话!),可以进一步达到这个目的。

考虑:您有一个公共方法A,它调用私有方法B。A和B都使用方法C。C被更改(可能由您更改,也可能由供应商更改),导致A开始测试失败。对B进行测试不是很有用吗,即使它是私有的,这样你就知道问题是在A使用C, B使用C,还是两者都有?

Testing private methods also adds value in cases where test coverage of the public interface is incomplete. While this is a situation we generally want to avoid, the efficiency unit testing depends both on the tests finding bugs and the associated development and maintenance costs of those tests. In some cases, the benefits of 100% test coverage may be judged insufficient to warrant the costs of those tests, producing gaps in the public interface's test coverage. In such cases, a well-targeted test of a private method can be a very effective addition to the code base.

如果私有方法定义良好(即,它有一个可测试的函数,并且不会随着时间的推移而改变),那么是的。我在有意义的地方测试所有可测试的东西。

例如,加密库可能会隐藏这样一个事实,即它使用一次仅加密8个字节的私有方法执行块加密。我会为此写一个单元测试——它并不意味着要改变,即使它是隐藏的,如果它真的坏了(例如,由于未来的性能增强),那么我想知道是私有函数坏了,而不仅仅是某个公共函数坏了。

它加快了以后的调试。

亚当

如果您不测试您的私有方法,您怎么知道它们不会崩溃呢?