使用 FsCheck 从 Xunit 测试中删除 Arb.registerByType 的使用

Removing usage of Arb.registerByType from Xunit test using FsCheck

我正在测试 Thoth.Json 编码器/解码器对的往返。

看起来像这样:

type CustomArbitrary =
  static member String() =
    Arb.Default.String()
    |> Arb.filter (not << isNull)

[<Fact>]
let ``Encode.foo Decode.foo round-trip`` () =
  let roundTrip (x : Foo) =
    let json =
      x
      |> Encode.foo
      |> Encode.toString 2

    let decoded =
      json
      |> Decode.fromString Decode.foo

    Ok x = decoded

  // Necessary?
  Arb.registerByType (typeof<CustomArbitrary>) |> ignore

  Check.QuickThrowOnFailure (roundTrip)

如果我不过滤掉 System.Stringnull 值,测试将失败。但是,null 不是 Foo 中的正确值,所以没关系。

但是,由于全局状态等原因,我不喜欢在这里使用 Arb.registerByType

如何重写此测试,以便 Arb.registerByType 不是必需的?

理想情况下,我会设计一次 FsCheck 配置并将其传递给每个测试。

使用原始 FsCheck

像这样创建一次配置:

let config =
    {
        FsCheck.Config.Default with
            Arbitrary = [ typeof<CustomArbitrary> ]
    }

然后用它来检查每个测试,如下所示:

Check.One(config, roundTrip)

使用FsCheck.Xunit

如果您切换到 Properties/Property 而不是 Fact,您甚至不需要显式 config 实例或 Check class:

open FsCheck.Xunit

[<Properties(Arbitrary=[| typeof<CustomArbitrary> |])>]
module MyTests =

    [<Property>]
    let ``Encode.foo Decode.foo round-trip`` (x : Foo) =
        let json =
          x
          |> Encode.foo
          |> Encode.toString 2

        let decoded =
          json
          |> Decode.fromString Decode.foo

        Ok x = decoded

    [<Property>]
    let ``Some other test`` () =
        true

有关此方法的更多信息 here

顺便说一句,在测试名称中使用 . 字符时要小心,因为一些测试框架(例如 Visual Studio)使用它们来定义测试层次结构。