FsUnit并检查浮点数的相等性

时间:2010-07-08 15:48:37

标签: f# nunit fsunit

我开始使用FsUnit来测试F#代码。它可以用F#样式表达断言,例如:

[<Test>]
member this.``Portugal voted for 23 countries in 2001 Eurovision contest``() =
    this.totalVotes 
    |> getYearVotesFromCountry "Portugal" 2001
    |> Seq.length
    |> should equal 23

注意我应该从FsUnit得到“应该等于23”。以下是FsUnit如何定义它:

让等于x = new EqualConstraint(x)

使用浮点数并不是那么简单。我必须使用EqualConstraint和Within方法。它自然适合C#:

Assert.That(result).Is.EqualTo(1).Within(0.05);

当然我希望能用F#写作:

result |> should equal 1 within 0.05

但这不起作用。我最终定义了一个新功能:

let almostEqual x = (new EqualConstraint(x)).Within(0.01)

或者如果我想参数化精度,我可以将其指定为第二个参数:

let equalWithin x y = (new EqualConstraint(x)).Within(y)

但它们都不漂亮。我想以更自然的方式为F#定义“内部”函数,因此它可以与相等的一起使用。 F#不支持方法重载,因此看起来我无法以这样的方式定义它,因此“相等”可以单独使用,也可以与“内部”一起使用。

有什么想法吗?

2 个答案:

答案 0 :(得分:12)

这是一个有趣的问题!我认为您不能以任何方式将within 0.05附加到should equal的现有定义中。为此,您需要向should函数添加参数,但需要在库中包含固定数量的参数。

在F#中优雅地写这个的一种方法是创建自定义运算符+/-。请注意,您仍然需要使用括号,但它看起来非常整洁:

0.9 |> should equal (1.0 +/- 0.5)

运算符只是构造一些需要在equal函数中显式处理的特殊类型的值。以下是实施:

type Range = Within of float * float
let (+/-) (a:float) b = Within(a, b)

let equal x = 
  match box x with 
  | :? Range as r ->
      let (Within(x, within)) = r
      (new EqualConstraint(x)).Within(within)
  | _ ->
    new EqualConstraint(x)

答案 1 :(得分:0)

术语说明:F#支持方法重载;它不支持重载 let-bound函数(模块中定义的'free'函数)。

你可以,例如使用点制作should.equal,以便equalshould对象上的一个方法,您可以重载该方法。虽然这仍然没有帮助,因为你不能超载curried参数。嗯。

好的,我提供的帮助不大。就个人而言,我不喜欢图书馆中这些类型的句法糖。