使用工厂构造函数测试私有类型

时间:2019-08-10 10:58:08

标签: f#

我已经创建了一些基本类型,目的是无法创建无效状态。例如:

type PositiveDecimal = private PositiveDecimal of decimal

[<RequireQualifiedAccess>]
module PositiveDecimal =

    let create num =
        if num >= 0m then
            num |> PositiveDecimal |> Ok
        else
            Error.validation None (sprintf "'%f' should be positive." num)

这将返回Result,其中包含成功创建的对象或自定义错误类型。

我发现对单元测试(使用MSTest)感到很尴尬:

[<TestMethod>]
member __.Create() =
    let actual = 
        PositiveDecimal.create 1m
        |> Result.map PositiveDecimal.value

    // This explicit type is unfortunately required because otherwise
    // they will have different error types :(.
    let expected : Result<_, Error.Error> = Ok 1m

    Assert.AreEqual(expected, actual)

如您所见,我必须将其映射回decimal,因为我无法通过其他来源创建PositiveDecimal

当然,我可以使用make构造函数internalInternalsVisibleTo,但是如果允许整个程序集忽略工厂,那将绕过整个安全点。有更好的方法来测试吗?

1 个答案:

答案 0 :(得分:1)

我可能不会为像您这样的智能构造函数编写一个测试,但是如果我正在编写一个,则可能会完全避免该问题,并进行一个测试是否成功的测试给出肯定的论点,即

member __.Create() =
    let res = PositiveDecimal.create 1m

    Assert.True(match res with Ok pd -> PositiveDecimal.value pd = 1M | _ -> false)

和另一个带有否定参数的失败案例(可以说是一个为零)。

或将两者合并在FsCheck属性中:

open FsCheck

let prop x = 
    let res = PositiveDecimal.create x
    match res with
    | Ok pd -> x >= 0M && PositiveDecimal.value pd = x 
    | Error _ -> x < 0M

Check.Quick prop