防止 FsCheck 生成 NaN 和无穷大数

5
我有一个嵌套很深的数据结构,其中有许多浮点数。我正在使用FsCheck来检查在序列化和反序列化后数据是否不变。
当一个浮点数是NaN或+/-无穷大时,这个属性会失败,但这种情况并不重要,因为我不希望这些值出现在实际数据中。
有没有办法防止FsCheck生成NaN和无穷大?
我已经尝试丢弃包含这些值的生成数据,但这使得测试非常缓慢,甚至在我写这篇文章时测试仍在运行,我怀疑它是否能够完成...

1
使用 NormalFloat 包装器 https://github.com/fsharp/FsCheck/blob/master/src/FsCheck/Arbitrary.fs#L28 https://github.com/fsharp/FsCheck/blob/master/src/FsCheck/Arbitrary.fs#L603 - Mauricio Scheffer
哦,很酷。那么,我该怎么做呢? :-) - phaz
将您的测试参数类型设置为 NormalFloat - Mauricio Scheffer
抱歉,我仍然不明白你想说什么。 应该生成的数据是记录的记录的记录(有点像),其中一些包含浮点数等其他内容。我希望在应该生成浮点数的所有位置上,都不要使用NaN或无穷大。 - phaz
你是自己编写了数据生成器还是使用内置的基于反射的生成器? - Kurt Schelfthout
我和@Phazyck有着相同的问题。在我的代码中,from<int>无法正常工作。FsCheck中的所有功能都非常复杂且未经记录,因此使用该框架的门槛非常高。例如,我编写了一个生成器来创建偶数。然后我用它创建了Arbitrary<int>,但它不起作用。请让它更简单并提供更好的文档支持。我们现在不需要更多的功能,我们需要更多的示例和文档。 - Endrju
2个回答

11

对于反射生成的包含浮点数(我猜你在使用)的类型,您可以通过编写以下类来覆盖默认的浮点数生成器:

type Overrides() =
    static member Float() =
        Arb.Default.Float()
        |> filter (fun f -> not <| System.Double.IsNaN(f) &&
                            not <| System.Double.IsInfinity(f)) 

然后调用:

Arb.register<Overrides>()

在FsCheck尝试生成类型之前,例如在测试设置或调用Check.Quick之前。

您可以检查register方法的结果以查看它如何将默认的任意实例与新实例合并; 它应该已经覆盖了它们。

如果您正在使用xUnit扩展,可以通过使用PropertyAttribute的Arbitraries参数来避免调用Arb.register:

[<Property(Arbitraries=Overides)>]

你介意举个例子详细讲解一下你最后一段的内容吗? - primfaktor

8
正如Mauricio Scheffer所说,您可以在测试参数中使用NormalFloat类型。
浮点数列表的简单示例:
open FsCheck

let f (x : float list) = x |> List.map id

let propFloat (x : float list) = x = (f x)

let propNormalFloat (xn : NormalFloat list) = 
    let x = xn |> List.map NormalFloat.get
    x = f x

Check.Quick propFloat
//Falsifiable, after 18 tests (13 shrinks) (StdGen (761688149,295892075)):
//[nan]

Check.Quick propNormalFloat
//Ok, passed 100 tests.

我猜这个方法在其他情况下可能也适用,就像你所举例的那些情况一样。问题是,数据不仅仅是一个浮点数列表或类似的东西,使得我可以将NormalFloat写成类型的一部分,而是一个包含各种地方的浮点数和其他类型的更复杂结构。我需要的是让FsCheck在任何需要浮点数的地方生成NormalFloats,无论数据看起来有多复杂,就像Kurt Schelfthout展示的那样。 :-) - phaz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接