如何忽略 FsUnit 断言中受歧视的联合案例的价值?
How can I ignore the value of a discriminated union case in FsUnit's assert?
如何在 FsUnit 的断言中忽略可区分联合案例的值?
举个例子:
type TransactionAttempt = {
Deposited:float
Requires:float
}
type RequestResult =
| Denied of TransactionAttempt
| Granted of Product
在我的测试中,我想这样做:
let display = balance |> select Pepsi
display |> should equal Denied
我不介意这样做:
display |> should equal (Denied _)
但是,我不得不这样做:
display |> should equal (Denied {Deposited=0.25; Requires=1.00})
请注意我必须对上面的表达式表达得多么明确。
因此,我只想知道它是否被拒绝了。我不关心细节。
实际测试如下:
[<Test>]
let ``Vending machine reflects more money required for selection``() =
// Setup
let balance = Quarter |> insert []
// Test
let display = balance |> select Pepsi
// Verify
display |> should equal (Denied {Deposited=0.25; Requires=1.00})
函数如下:
let select product balance =
let attempt = { Deposited=balance
Requires=product |> getPrice }
let paidInFull = attempt.Deposited >= attempt.Requires
if not paidInFull then
Denied attempt
else Granted product
这是整个域:
module Machine
type Deposit =
| Nickel
| Dime
| Quarter
| OneDollarBill
| FiveDollarBill
type TransactionAttempt = {
Deposited:float
Requires:float
}
type State =
| OutOfService
| PaymentReceived of Deposit
| WaitingForSelection
| NotPaidInFull of TransactionAttempt
type Product =
| Pepsi
| Coke
| Sprite
| MountainDew
type RequestResult =
| Denied of TransactionAttempt
| Granted of Product
(* Functions *)
open System
let display = function
| OutOfService -> "Out of Service"
| WaitingForSelection -> "Make selection"
| NotPaidInFull attempt -> sprintf "%s Required" ((attempt.Requires - attempt.Deposited).ToString("C2"))
| PaymentReceived deposit -> match deposit with
| Nickel -> "5¢"
| Dime -> "10¢"
| Quarter -> "25¢"
| OneDollarBill -> ".00"
| FiveDollarBill -> ".00"
let getBalance coins =
coins |> List.fold (fun acc d -> match d with
| Nickel -> acc + 0.05
| Dime -> acc + 0.10
| Quarter -> acc + 0.25
| OneDollarBill -> acc + 1.00
| FiveDollarBill -> acc + 5.00) 0.00
let insert balance coin =
coin::balance |> getBalance
let getPrice = function
| Pepsi -> 1.00
| Coke -> 1.00
| Sprite -> 1.00
| MountainDew -> 1.00
let select product balance =
let attempt = { Deposited=balance
Requires=product |> getPrice }
let paidInFull = attempt.Deposited >= attempt.Requires
if not paidInFull then
Denied attempt
else Granted product
我能想到的最简单的事情就是为你想要的检查写一个谓词:
let isDenied du =
match du with
| Denied _ -> true
| _ -> false
或者因为 let f x = match x with ...
等同于 let f = function ...
,那可能是:
let isDenied = function Denied _ -> true | _ -> false
然后你的测试看起来像:
display |> isDenied |> should be True
请注意 True
,大写 T 是一个约束条件。如果您要与布尔值进行比较,那么它将是
display |> isDenied |> should equal true
如果您发现必须编写大量这些自定义谓词,可能有一个更通用的解决方案,涉及为 NUnit 或 XUnit 或您在后端使用的任何测试框架编写自定义约束。但是作为 F# 的新手,您可能应该先使用简单的解决方案,然后再进行概括。
P.S。如果您决定编写自定义约束,请查看 https://github.com/fsprojects/FsUnit/blob/master/src/FsUnit.NUnit/FsUnit.fs (if you're using NUnit) or https://github.com/fsprojects/FsUnit/blob/master/src/FsUnit.Xunit/FsUnit.fs(如果您使用的是 XUnit)以获取灵感。
如何在 FsUnit 的断言中忽略可区分联合案例的值?
举个例子:
type TransactionAttempt = {
Deposited:float
Requires:float
}
type RequestResult =
| Denied of TransactionAttempt
| Granted of Product
在我的测试中,我想这样做:
let display = balance |> select Pepsi
display |> should equal Denied
我不介意这样做:
display |> should equal (Denied _)
但是,我不得不这样做:
display |> should equal (Denied {Deposited=0.25; Requires=1.00})
请注意我必须对上面的表达式表达得多么明确。
因此,我只想知道它是否被拒绝了。我不关心细节。
实际测试如下:
[<Test>]
let ``Vending machine reflects more money required for selection``() =
// Setup
let balance = Quarter |> insert []
// Test
let display = balance |> select Pepsi
// Verify
display |> should equal (Denied {Deposited=0.25; Requires=1.00})
函数如下:
let select product balance =
let attempt = { Deposited=balance
Requires=product |> getPrice }
let paidInFull = attempt.Deposited >= attempt.Requires
if not paidInFull then
Denied attempt
else Granted product
这是整个域:
module Machine
type Deposit =
| Nickel
| Dime
| Quarter
| OneDollarBill
| FiveDollarBill
type TransactionAttempt = {
Deposited:float
Requires:float
}
type State =
| OutOfService
| PaymentReceived of Deposit
| WaitingForSelection
| NotPaidInFull of TransactionAttempt
type Product =
| Pepsi
| Coke
| Sprite
| MountainDew
type RequestResult =
| Denied of TransactionAttempt
| Granted of Product
(* Functions *)
open System
let display = function
| OutOfService -> "Out of Service"
| WaitingForSelection -> "Make selection"
| NotPaidInFull attempt -> sprintf "%s Required" ((attempt.Requires - attempt.Deposited).ToString("C2"))
| PaymentReceived deposit -> match deposit with
| Nickel -> "5¢"
| Dime -> "10¢"
| Quarter -> "25¢"
| OneDollarBill -> ".00"
| FiveDollarBill -> ".00"
let getBalance coins =
coins |> List.fold (fun acc d -> match d with
| Nickel -> acc + 0.05
| Dime -> acc + 0.10
| Quarter -> acc + 0.25
| OneDollarBill -> acc + 1.00
| FiveDollarBill -> acc + 5.00) 0.00
let insert balance coin =
coin::balance |> getBalance
let getPrice = function
| Pepsi -> 1.00
| Coke -> 1.00
| Sprite -> 1.00
| MountainDew -> 1.00
let select product balance =
let attempt = { Deposited=balance
Requires=product |> getPrice }
let paidInFull = attempt.Deposited >= attempt.Requires
if not paidInFull then
Denied attempt
else Granted product
我能想到的最简单的事情就是为你想要的检查写一个谓词:
let isDenied du =
match du with
| Denied _ -> true
| _ -> false
或者因为 let f x = match x with ...
等同于 let f = function ...
,那可能是:
let isDenied = function Denied _ -> true | _ -> false
然后你的测试看起来像:
display |> isDenied |> should be True
请注意 True
,大写 T 是一个约束条件。如果您要与布尔值进行比较,那么它将是
display |> isDenied |> should equal true
如果您发现必须编写大量这些自定义谓词,可能有一个更通用的解决方案,涉及为 NUnit 或 XUnit 或您在后端使用的任何测试框架编写自定义约束。但是作为 F# 的新手,您可能应该先使用简单的解决方案,然后再进行概括。
P.S。如果您决定编写自定义约束,请查看 https://github.com/fsprojects/FsUnit/blob/master/src/FsUnit.NUnit/FsUnit.fs (if you're using NUnit) or https://github.com/fsprojects/FsUnit/blob/master/src/FsUnit.Xunit/FsUnit.fs(如果您使用的是 XUnit)以获取灵感。