5

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
4

1 に答える 1

10

私が思いつく最も簡単なことは、必要なチェックの述語を書くことです。

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 を使用している場合) からインスピレーションを得てください。

于 2016-07-15T02:24:24.953 に答える