9

値が判別共用体の特定のケースであることを確認したいのですが、含まれているデータも確認する必要はありません。私の動機は、各単体テストで 1 つのことだけをテストすることです。

例は次のとおりです (最後の 2 行でコンパイル エラーが発生します)。

module MyState

open NUnit.Framework
open FsUnit

type MyState =
    | StateOne of int
    | StateTwo of int

let increment state =
    match state with
    | StateOne n when n = 10 -> StateTwo 0
    | StateOne n -> StateOne (n + 1)
    | StateTwo n -> StateTwo (n + 1)

[<Test>]
let ``incrementing StateOne 10 produces a StateTwo`` ()=
    let state = StateOne 10
    (increment state) |> should equal (StateTwo 0)             // works fine
    (increment state) |> should equal (StateTwo _)             // I would like to write this...
    (increment state) |> should be instanceOfType<StateTwo>    // ...or this

これは FsUnit で実行できますか?

私はこの答えを知っていますが、ケースごとに一致する関数を記述する必要はありません (私の実際のコードでは、2 つ以上あります)。

4

4 に答える 4

9

リフレクションの使用を気にしない場合は、この回答isUnionCaseの関数が便利です。

increment state 
|> isUnionCase <@ StateTwo @>
|> should equal true

値を比較する前に関数呼び出しが必要なため、少し冗長であることに注意してください。

同様のより軽いアプローチは、タグの比較です。

// Copy from https://stackoverflow.com/a/3365084
let getTag (a:'a) = 
  let (uc,_) = Microsoft.FSharp.Reflection.FSharpValue.GetUnionFields(a, typeof<'a>)
  uc.Name

increment state 
|> getTag
|> should equal "StateTwo"

これはタイプ セーフではなく、共用体のケース名のスペルを簡単に間違える可能性があることに注意してください。

私がすることは、比較目的で同様の DU を作成することです。

type MyStateCase =
    | StateOneCase
    | StateTwoCase

let categorize = function
    | StateOne _ -> StateOneCase
    | StateTwo _ -> StateTwoCase

このように、categorize一度定義すれば、それを複数回使用できます。

increment state
|> categorize
|> should equal StateTwoCase
于 2013-09-25T13:10:17.030 に答える
3

FSUnit は、このユース ケースを直接サポートしていないようです (またはサポートしていないかどうかはわかりません)。

私が見つけた次善の策はTestResult、次のような型を宣言し、一致を使用して結果をこの型に減らすことです。

type TestResult =
| Pass
| Fail of obj

これが削減マッチです

let testResult =
    match result with
    | OptionA(_) -> Pass
    | other -> Fail(other)

should equalこれで、正しい結果を保証するために使用できます。

testResult  |> should equal Pass

このソリューションの利点は強力な型付けですが、さらに重要なことは、失敗した場合に無効な結果が何であったかを確認できることです。

于 2016-11-24T05:23:37.870 に答える
0

type の値に制限されているにもかかわらず、 FsUnitが特定の共用体ケースに対するアサーションを既にサポートしている場合はどうなるMicrosoft.FSharp.Core.Choice<_,...,_>でしょうか?

これを、リフレクションを使用してユニオンケース名と照合するマルチケースアクティブパターンで活用しましょう。

open System.Reflection
open Microsoft.FSharp.Reflection

let (|Pass|Fail|) name (x : obj) =
    let t = x.GetType()
    if FSharpType.IsUnion t &&
        t.InvokeMember("Is" + name,
            BindingFlags.GetProperty, null, x, null )
        |> unbox then Pass
    else Fail x

現在動作しているはずです:

increment state
|> (|Pass|Fail|) "StateTwo"
|> should be (choice 1)
于 2016-11-24T20:38:03.197 に答える