我正在使用 FsCheck 在 F# 中进行一些属性测试。因此,我希望保证某些条件始终成立,无论输入参数如何。
考虑我为float
值定义了一个平凡的恒等函数。
let floatId (x : float) = x
然后我定义了一个我知道应该始终持有的函数的测试:
let ``floatId returns input float`` x = floatId x = x
这是一个微不足道的测试,我只是检查调用我的浮点标识函数是否返回与输入浮点数相同的结果。
然后我将此函数插入 FsCheck:
Check.Quick ``floatId returns input float``
不幸的是,这个属性测试失败了!
Falsifiable, after 21 tests (0 shrinks) (StdGen (1872424299,296201373)): Original: nan
当然,回头看,很明显这会发生,我们知道nan <> nan
。
由于 F# 中的结构比较,这也可能会困扰(稍微)更复杂的涉及集合的测试用例。
如果我为浮动列表设计类似的功能:
let listFloatId (lst : float list) = lst
let ``listFloatId returns input float list`` lst = listFloatId lst = lst
Falsifiable, after 6 tests (3 shrinks) (StdGen (1874889363,296201373)): Original: [nan; 2.0; 2.25; 4.940656458e-324] Shrunk: [nan]
又是同样的问题!
显然,我可以通过创建自己的相等测试函数来解决这个问题,这对于float
值来说很好,但是扩展到集合变得更加复杂,list
因为我必须开始使用List.forall2
我的自定义相等函数并且通常将我的代码专门用于每个单独的集合类型.
在 F# 中是否有解决此问题的一般方法?