我已经阅读了这篇关于如何测试私有方法的文章。我通常不测试它们,因为我总是认为只测试将从对象外部调用的公共方法更快。你测试私有方法吗?我应该一直测试它们吗?
当前回答
如果您正在开发测试驱动(TDD),您将测试您的私有方法。
其他回答
我们通过推断来测试私有方法,我的意思是我们寻找总类测试覆盖率至少为95%,但我们的测试只调用公共方法或内部方法。为了获得覆盖,我们需要根据可能发生的不同场景对公众/内部人员进行多次调用。这使得我们的测试更专注于它们所测试的代码的目的。
特朗皮对你链接的帖子的回答是最好的。
I understand the point of view where private methods are considered as implementations details and then don't have to be tested. And I would stick with this rule if we had to develop outside of the object only. But us, are we some kind of restricted developers who are developing only outside of objects, calling only their public methods? Or are we actually also developing that object? As we are not bound to program outside objects, we will probably have to call those private methods into new public ones we are developing. Wouldn't it be great to know that the private method resist against all odds?
我知道有些人会回答说,如果我们正在开发另一个公共方法到那个对象中,那么这个方法应该被测试,就是这样(私有方法可以在没有测试的情况下继续存在)。但这也适用于一个对象的任何公共方法:当开发一个web应用程序时,一个对象的所有公共方法都是从控制器方法调用的,因此可以认为是控制器的实现细节。
那么为什么我们要单元测试对象呢?因为这是非常困难的,不是说不可能,以确保我们正在测试控制器的方法与适当的输入将触发底层代码的所有分支。换句话说,我们在堆栈中的位置越高,测试所有行为就越困难。私有方法也是如此。
对我来说,私人方法和公共方法之间的界限是测试时的心理标准。对我来说更重要的标准是:
该方法是否在不同的地方被多次调用? 这种方法是否复杂到需要测试?
它不仅涉及公共或私有方法或函数,还涉及实现细节。私有函数只是实现细节的一个方面。
毕竟,单元测试是一种白盒测试方法。例如,无论谁使用覆盖率分析来识别到目前为止在测试中被忽略的代码部分,都将进入实现细节。
A)是的,你应该测试实现细节:
考虑一个排序函数,如果有多达10个元素,则出于性能考虑使用BubbleSort的私有实现,如果有超过10个元素,则使用不同排序方法(例如堆排序)的私有实现。公共API是排序函数的API。但是,您的测试套件更好地利用了实际上使用了两种排序算法的知识。
在本例中,当然可以在公共API上执行测试。然而,这需要有大量的测试用例来执行具有10个以上元素的排序函数,以便对堆排序算法进行充分的测试。这种测试用例的单独存在表明测试套件连接到功能的实现细节。
如果排序函数的实现细节发生了变化,可能是两种排序算法之间的限制发生了变化,或者堆排序被归并排序取代了,或者其他:现有的测试将继续工作。然而,它们的价值是值得怀疑的,它们可能需要重新工作,以更好地测试更改后的排序函数。换句话说,尽管测试是在公共API上进行的,但仍然需要进行维护工作。
B)如何测试实现细节
许多人认为不应该测试私有函数或实现细节的一个原因是,实现细节更有可能改变。这种更高的更改可能性至少是将实现细节隐藏在接口后面的原因之一。
现在,假设接口背后的实现包含更大的私有部分,可以选择在内部接口上进行单独的测试。有些人认为,这些部分不应该在私人的时候进行测试,它们应该变成公共的东西。一旦公开,对代码进行单元测试就可以了。
这很有趣:虽然接口是内部的,但它很可能会改变,这是一个实现细节。使用相同的接口,将其公开可以进行一些神奇的转换,即将其转换为不太可能更改的接口。显然,这种论证有一些缺陷。
但是,这背后仍然有一些事实:在测试实现细节时,特别是使用内部接口时,应该尽量使用可能保持稳定的接口。然而,某些接口是否可能是稳定的,不能简单地根据它是公共的还是私有的来确定。在我工作过一段时间的项目中,公共接口也经常发生变化,而许多私有接口多年未动。
不过,“先从正门走”是一个很好的经验法则(见http://xunitpatterns.com/Principles%20of%20Test%20Automation.html)。但请记住,这是“前门优先”,而不是“只有前门”。
C)总结
还要测试实现细节。更喜欢在稳定接口(公共或私有)上进行测试。如果实现细节发生变化,也需要修改对公共API的测试。把私人的东西变成公共的东西并不能神奇地改变它的稳定性。
我倾向于遵循Dave Thomas和Andy Hunt在他们的书《实用单元测试》中的建议:
一般来说,为了不破坏任何封装 测试(或者就像妈妈常说的,“不要暴露你的私处!”)。大多数 此时,您应该能够通过执行类的 公共方法。如果隐藏了重要的功能 在私人或受保护访问的背后,这可能是一个警告信号 还有一群人在里面挣扎着想出来。
但有时我无法阻止自己测试私有方法,因为它给了我一种安全感,我正在构建一个完全健壮的程序。
如果我发现私有方法非常庞大、复杂或重要到需要自己的测试,我就把它放在另一个类中,并在那里将它设为公共(方法对象)。然后,我可以轻松地测试以前私有但现在是公共的方法,它现在存在于自己的类中。
推荐文章
- 使用Moq验证特定参数
- 如何为python模块的argparse部分编写测试?
- python中的assertEquals和assertEqual
- 如何使用“测试”包打印Go测试?
- 设计模式:工厂vs工厂方法vs抽象工厂
- 如何在IntelliJ中为整个项目配置“缩短命令行”方法
- 为什么处理排序数组比未排序数组慢?
- toBe(true) vs toBeTruthy() vs toBeTrue()
- 构造函数何时抛出异常是正确的?
- 使用Mockito测试抽象类
- 什么是“一级”对象?
- 什么时候应该使用Debug.Assert()?
- 为什么浮点数不准确?
- 使用Moq模拟单元测试的异步方法
- 你的项目没有引用“. net framework,Version=v4.6.2”框架。在“TargetFrameworks”中添加对“.NETFramework,Version=v4.6.2”的引用