f# - 如何使用FsUnit检查歧视工会的情况?

标签 f# discriminated-union fsunit

我想检查一个值是否属于已区分联合的特殊情况,而不必检查任何包含的数据。我的动机是每次单元测试只能测试一件事。

示例如下(最后两行给出了编译错误):

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中完成吗?

我知道this answer,但不希望不必为每种情况编写匹配函数(在我的真实代码中,远远超过两个)。

最佳答案

如果您不介意使用反射,那么this answer中的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

关于f# - 如何使用FsUnit检查歧视工会的情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19001567/

相关文章:

functional-programming - 使用连续传递样式简化多路树遍历

c# - 为什么 Microsoft F# 指南不建议从 C# 使用的代码中返回元组?

F#:获取源文件以自动评估

f# - 将 Elmish `dispatch` 消息从父组件传递/转换到子组件

f# - 如何在 F# 中正确使用 NUnit?

visual-studio - f# 的响应式(Reactive)扩展

generics - f# 可区分联合泛型

f# - 在 f# 中废弃你的样板

f# - 如何使用 FsCheck 实现多参数生成?