我们知道编写JUnit测试可以演示代码中的一条特定路径。
我的一位同事评论说:
手动编写单元测试是“ 通过示例证明”。
他来自具有诸如Quickcheck之类的工具的Haskell的背景,并且具有推理类型程序行为的能力。
他的意思是,此方法未尝试使用许多其他输入组合,而您的代码并未经过测试。
我的问题是:手动编写单元测试示例验证吗?
我们知道编写JUnit测试可以演示代码中的一条特定路径。
我的一位同事评论说:
手动编写单元测试是“ 通过示例证明”。
他来自具有诸如Quickcheck之类的工具的Haskell的背景,并且具有推理类型程序行为的能力。
他的意思是,此方法未尝试使用许多其他输入组合,而您的代码并未经过测试。
我的问题是:手动编写单元测试示例验证吗?
Answers:
如果您是随机选择要测试的输入,那么我想您可能正在行使“示例验证”逻辑谬误。
但是好的单元测试永远都做不到。相反,它们处理范围和边缘情况。
例如,如果要为接受整数作为输入的绝对值函数编写单元测试,则无需测试输入的每个可能值即可证明代码有效。要进行全面测试,您只需要五个值:-1、0、1,以及输入整数的最大值和最小值。
这五个值测试功能的每个可能范围和边缘情况。您无需测试其他所有可能的输入值(即整数类型可以代表的每个数字),即可获得该函数适用于所有输入值的高置信度。
int foo(int x) { return 1234/(x - 100); }
。还要注意(取决于您要测试的内容),您可能需要确保无效(“超出范围”)输入返回正确的结果(例如,“ find_thing(thing)”正确返回某种“未找到”状态) (如果找不到)。
-Inf
,Inf
,NaN
,1e-100
,-1e-100
,-0
,2e200
...我宁愿没有到所有手工做的那些。
任何软件测试都类似于“示例验证”,而不仅仅是使用JUnit之类的工具进行单元测试。但这不是新的见识,Dijkstra引用了1960年的话,内容基本相同:
“测试表明存在缺陷,而不是没有缺陷”
(只需将“显示”一词替换为“证明”)。但是,对于生成随机测试数据的工具也是如此。实际功能的可能输入数量通常比生成的测试用例数量要大几个数量级,而不取决于生成这些用例的方法,并根据宇宙时期内的预期结果进行验证,因此即使使用生成器工具生成大量测试数据,也不能保证不会遗漏一个可能已经检测到某个错误的测试用例。
随机测试有时可能会发现一个错误,而该错误被手动创建的测试用例忽略了。但是总的来说,对要测试的功能进行精心的测试,并确保使用尽可能少的测试用例获得完整的代码和分支覆盖范围,会更有效率。有时将手动和随机生成的测试结合起来是一种可行的策略。此外,在使用随机测试时,必须注意以可重复的方式获得结果。
因此,手动创建的测试绝不会比随机生成的测试差,通常恰恰相反。