Как я могу игнорировать значение дискриминационного объединенного случая в утверждении FsUnit?
Как я могу игнорировать значение дискриминационного объединенного случая в утверждении 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 -> "$1.00"
| FiveDollarBill -> "$5.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
1 ответ
Самое простое, что я могу придумать, это написать предикат для проверки, которую вы хотите:
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#, вам, вероятно, следует сначала воспользоваться простым решением, а затем обобщить его.
PS Если вы решили написать собственное ограничение, посмотрите https://github.com/fsprojects/FsUnit/blob/master/src/FsUnit.NUnit/FsUnit.fs (если вы используете NUnit) или https://github.com/fsprojects/FsUnit/blob/master/src/FsUnit.Xunit/FsUnit.fs (если вы используете XUnit) для вдохновения.