使用FsCheck生成记录

3
我想使用FsCheck(与XUnit一起)创建类型为:type QueryRequest = {Symbol: string; StartDate: DateTime; EndDate: DateTime}的记录,其中Symbol仅限于3个选项 - ORCLIBMAAPL,而StartDateEndDate仅限于2000年1月1日至2019年1月1日之间的范围。
然而,我不清楚该如何继续。我应该使用Arb.generate<T>Arb.Default或其他一些实用程序来基于测试用例生成和缩小?
更新1 有关生成记录问题的后续问题,请单击此处
Original:
{ Symbol = ""
  StartDate = 8/9/2057 4:07:10 AM
  EndDate = 10/14/2013 6:15:32 PM }
Shrunk:
{ Symbol = ""
  StartDate = 8/9/2057 12:00:00 AM
  EndDate = 10/14/2013 12:00:00 AM }

更新2

以下是测试套件代码:

namespace Parser

open Xunit
open FsCheck.Xunit
open DataGenerators

module Tests =
    [<Fact>]
    let ``sanity check`` () =
        let expected = true
        let actual = true
        Assert.Equal(expected, actual)

    [<Property(Arbitrary = [|typeof<StockTwitGenerator>|])>]
    let ``validate queries`` (q: QueryRecord) =
        q.EndDate > q.StartDate

“it doesn’t quite work” 不是一个好的问题描述。我建议您删除更新并提出单独的问题。 - CaringDev
1
@CaringDev同意了,提出了一个分开的跟进问题。在原帖更新中提供了链接。 - Ari
2个回答

3

3

当您有限制将值限制为给定类型的所有允许值中的一小部分时,构造有效值比过滤更容易且更安全1

鉴于...

open FsCheck
open System

type QueryRequest = {Symbol: string; StartDate: DateTime; EndDate: DateTime}

我们可以先创建符号生成器:

let symbols = ["ORCL"; "IBM"; "AAPL"]
let symbol = Gen.elements symbols

以及日期范围

let minDate = DateTime(2000, 1, 1)
let maxDate = DateTime(2019, 1, 1)
let dateRange = maxDate - minDate
let date =
    Gen.choose (0, int dateRange.TotalDays)
    |> Gen.map (float >> minDate.AddDays)

请注意,Gen.choose仅接受int范围。我们可以通过生成允许的日期差的最大随机偏移量来解决,并将其映射回DateTime
使用这些,我们可以构建一个QueryRequest生成器...
let query =
    gen {
        let! s = symbol
        let! d1 = date
        let! d2 = date
        let startDate, endDate = if d1 < d2 then d1, d2 else d2, d1 
        return { Symbol = s; StartDate = startDate; EndDate = endDate }
    }

type MyGenerators =
  static member QueryRequest() =
      {new Arbitrary<QueryRequest>() with
          override _.Generator = query }

... 注册 ...

Arb.register<MyGenerators>()

最后测试:

let test { Symbol = s; StartDate = startDate; EndDate = endDate } =
    symbols |> Seq.contains s && startDate >= minDate && endDate <= maxDate && startDate <= endDate

Check.Quick test

1 FsCheck文档

确保谓词被满足的概率很高。


你是怎么知道 gen 会接受一个计算表达式的? - Ari
谢谢,我在原文中跳到了示例部分。对于其他人的参考,关于计算表达式的解释从提供的链接的第二段开始。 - Ari
当使用您上面提供的生成器执行测试用例时,这些用例包括错误/格式不正确的记录(请参见帖子中的更新示例),这些记录缺少符号,并且结束日期早于开始日期。有什么想法是什么问题? - Ari
你是如何执行测试的?你确定已经注册了生成器吗?当我执行以上操作时,即使进行了数万次的执行,我也没有得到错误的数据... - CaringDev
我更新了代码,包括测试套件。本质上,我执行了dotnet test,期望它会运行所有已识别的测试。这正如预期的那样发生了,但显然问题是使用了默认的任意实例而不是自定义的“StockTwitGenerator”。为了解决这个问题,我在属性属性中指定了任意值(请参见更新2)。无论是否注册生成器,我都必须指定此值,即 Arb.register<StockTwitGenerator>() |> ignore - Ari
显示剩余2条评论

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