单元测试主要有两种方式来验证待验证代码是否正常工作:通过测试状态和通过测试调用。二者有什么分别呢?
测试状态意味着只去验证待测代码返回的结果是否正确
1 | public void testSortNumbers() { |
测试调用意味着要验证待测代码确实正确地调用了某些方法
1 | public void testSortNumbers_quicksortIsUsed() { |
第二种测试(测试调用)可能会使得测试覆盖率比较高,但TA并不能告诉你待测的排序算法是否正常工作,只能知道quicksort.sort确实被调用了。这也是为什么在大多数场景下,都想要测试状态而不是测调用。
总的来说,调用在正确性不止依赖于返回值时才需要测试。在上述的例子中,只有在“quicksort是否被调用真的很重要时(比如,如果用了其他排序算法会导致方法执行很慢)”,才应该去测试调用,否则测试调用就真的没有必要。
一些其他可能会需要测试调用的场景
- 待测代码调用了一个方法,该方法在不同的调用顺序及调用次数下,表现完全不同,例如有副作用(例如,希望保证只会发送一封邮件),延迟(例如,想要确保只会产生确定次数的磁盘访问)或者多线程问题(比如,如果以错误的顺序访问,会导致产生死锁)。测试调用保证如果这些方法没有被正确调用,测试用例就挂。
- 在测试UI,且UI的渲染细节从UI逻辑中抽象分离出去了(例如使用MVC或MVP)。在测试Controller/Presenter时,只会关心View的具体方法确实被调用了,而不是去关心真的渲染成了什么样,因此你可以测与View之间的调用。类似的,当测试View时,你可以测与Controller/Presenter之间的调用。
文章翻译自:
https://testing.googleblog.com/2013/03/testing-on-toilet-testing-state-vs.html