f# - 如何在 FsUnit 的断言中忽略有区别的联合案例的值(value)?

标签 f# fsunit

如何在 FsUnit 的断言中忽略有区别的联合案例的值(value)?

举个例子:

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

最佳答案

我能想到的最简单的事情是为您想要的检查编写一个谓词:

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,是一个约束。如果您要与 bool 值进行比较,那么它将是
display |> isDenied |> should equal true

如果您发现必须编写大量这些自定义谓词,则可能有一个更通用的解决方案,涉及为 NUnit 或 XUnit 或您在后端使用的任何测试框架编写自定义约束。但作为 F# 的相对新手,您可能应该先使用简单的解决方案,然后再对其进行概括。

附言如果您决定编写自定义约束,请查看 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)以获得灵感。

关于f# - 如何在 FsUnit 的断言中忽略有区别的联合案例的值(value)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38385602/

相关文章:

math - 帮助! Math.PI 在 F# CTP 中去了哪里?

F#序列比较

f# - FsUnit 不匹配异常 - F#

f# - FsUnit.Xunit 列表应该包含一个 x 使得 f x

optimization - 如何在 F# 中优化此代码以提高速度,以及为什么一个部分执行两次?

list - F#创建x的倍数列表?

f# - F# 项目中的 FsUnit、NUnit 引用

inheritance - 对象表达式和错误 FS0419 : 'base' values may only be used to make direct calls to the base implementations of overridden members

algorithm - F# 数学库 - 计算中位数