我有这个 fscheck nunit 测试,它生成两条记录,然后我必须更新这两条记录,以便两条记录的 Direction 属性始终具有不同的值
[<Property( Verbose = true )>]
let ``calculate Net Worth 2`` (first:Bill,second:Bill) =
let owing = { first with Direction = Out }
let payCheck = { second with Direction = In }
let compositeBill = {
Bills = [| owing; payCheck |]
}
let netWorth = calculateNetWorth compositeBill
Assert.AreEqual(payCheck.Amount - owing.Amount,netWorth)
我不想手动设置 Direction = In 或 Direction = In ,我想使用生成器来指定它。
这样的生成器会是什么样子?
我想留下这样的代码
[<Property( Verbose = true )>]
let ``calculate Net Worth 2`` (first:Bill,second:Bill) =
let compositeBill = {
Bills = [| owing; payCheck |]
}
let netWorth = calculateNetWorth compositeBill
Assert.AreEqual(payCheck.Amount - owing.Amount,netWorth)
这是我尝试过的,但没有成功
type BillsGen =
static member Bill () =
let debit =
Arb.generate<Bill>
|> Gen.map (fun dt -> { dt with Direction = Out} )
let credit =
Arb.generate<Bill>
|> Gen.map (fun dt -> { dt with Direction = In} )
Gen.oneof[ debit; credit ]
[<SetUp>]
let setup () =
do Arb.register<BillsGen>() |> ignore
谢谢
这是我的一些类型
type Direction =
| In
| Out
type Bill = {
Direction : Direction
}
type CompositeBill = {
Bills : Bill []
}
最佳答案
我没有基于属性的测试经验,但我认为您可以通过创建一个代表受约束的输入值的新类型来做到这一点。然后您可以使用Gen.zip
在您的生成器中组合两个生成器来构建该类型的值。
type BillsInOut = BillsInOut of Bill * Bill
type BillsInOutGen =
static member BillsInOut () =
{ new Arbitrary<BillsInOut>() with
override x.Generator =
let credit =
Arb.generate<Bill>
|> Gen.map (fun dt -> { dt with Direction = In })
let debit =
Arb.generate<Bill>
|> Gen.map (fun dt -> { dt with Direction = Out })
Gen.zip credit debit |> Gen.map BillsInOut }
一旦你运行 Arb.register<BillsInOutGen>()
,您可以将此新类型作为测试参数,并且此属性应保持:
let property (BillsInOut (inBill, outBill)) =
inBill.Direction = In && outBill.Direction = Out
编辑:另一种方法
我突然想到,由于这两个账单是独立的,因此可以单独生成它们,这样就不需要将生成器压缩在一起,并且可以根据需要获得不同类型的账单:
type BillIn = BillIn of Bill
type BillOut = BillOut of Bill
type BillInOutGen =
static member BillIn () =
{ new Arbitrary<BillIn>() with
override x.Generator =
Arb.generate<Bill> |> Gen.map (fun dt -> BillIn { dt with Direction = In }) }
static member BillOut () =
{ new Arbitrary<BillOut>() with
override x.Generator =
Arb.generate<Bill> |> Gen.map (fun dt -> BillOut { dt with Direction = Out }) }
Arb.register<BillInOutGen>()
使用这些的属性现在看起来像这样:
let property (BillIn inBill) (BillOut outBill) =
inBill.Direction = In && outBill.Direction = Out
关于f# - 如何使用 FsCheck 生成器生成两条相同类型的记录,其中一条记录的属性与另一条记录不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44492279/