【问题标题】:Testing functions returning option<T>测试函数返回 option<T>
【发布时间】:2021-12-29 12:56:36
【问题描述】:

考虑对将strings of constrained length 定义为表示用户名的类型的模块进行单元测试:

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&lt;T&gt; 的函数的单元测试,该函数不需要显式检查“不愉快”路径(例如 | None -&gt; Assert.True(false))?我愿意为 UserName 模块添加更多类型和/或函数,以使其更易于测试。

【问题讨论】:

  • 我猜你忘了在第一个 sn-p type T = UserName of string 中将 ctor 设为私有?除非您将构造函数设为私有,否则您尝试执行的操作应该有效。

标签: unit-testing f# fsunit


【解决方案1】:

value 应用到Some 的内部,然后进行比较:

UserName.create "validname" 
  |> Option.map UserName.value
  |> should equal (Some "validname")

【讨论】:

    猜你喜欢
    • 2020-06-05
    • 2017-02-04
    • 2016-12-26
    • 1970-01-01
    • 1970-01-01
    • 2019-12-11
    • 1970-01-01
    • 2020-11-28
    • 1970-01-01
    相关资源
    最近更新 更多