0

考虑对定义长度受限字符串的模块进行单元测试,作为表示用户名的类型:

module UserName

type T = UserName of string
let create (userName : string) =
    if userName.Length >= 6 && userName.Length <= 16 
    then Some (UserName userName)
    else None
let apply f (UserName userName) = f userName
let value userName = apply id userName

确保函数返回None无效输入的单元测试看起来很简单:

[<Fact>]
let ``UserName must have at least six characters`` () =
    UserName.create "aaa" |> should equal None

但是,针对函数返回的情况的单元测试Some似乎需要额外的一行来保证match表达式的完整性:

[<Fact>]
let ``Valid UserName`` () =
    match UserName.create "validname" with
    | Some result ->
        UserName.value result |> should equal "validname"
    | None -> Assert.True(false)

这对我来说看起来不对,因为我的测试必须定义代码来测试无论如何都必须产生失败的“不愉快”路径。

我希望我可以写这个

[<Fact>]
let ``Valid UserName`` () =
    UserName.create "validname" |> should equal (Some (UserName "validname"))

但它不会编译(未定义值或构造函数“用户名”)。

有没有办法编写一个option<T>不需要明确检查“不愉快”路径(例如| None -> Assert.True(false))的函数返回的单元测试?我愿意为UserName模块添加更多类型和/或功能以使其更易于测试。

4

1 回答 1

4

value在里面Some再对比:

UserName.create "validname" 
  |> Option.map UserName.value
  |> should equal (Some "validname")
于 2021-12-29T14:13:30.890 回答