我已经创建了一些基本类型,目的是无法创建无效状态。例如:
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构造函数internal
和InternalsVisibleTo
,但是如果允许整个程序集忽略工厂,那将绕过整个安全点。有更好的方法来测试吗?
答案 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