在 F# 中如何对私有方法进行单元测试

4

假设我们有一个类

type ThisClassIsComplicated () = 
    let calculateSomething a b =
        a + b 

在这种情况下,calculateSomething 很简单,但如果它更加复杂,验证在那里进行的计算是否正确可能是有意义的。
使用单元测试框架来测试私有方法可能是有意义的。
我的问题是:如何在 F#中对私有方法进行单元测试?
一些随机想法:
所选答案here建议使用 InternalsVisibleTo 属性,但这只适用于 internal 方法
如果有的话,F# 的特定路线是什么?这在 F# 设计方面是否更好?
let calculateSomething a b = a + b 

type ThisClassIsComplicated () = 
    member this.Calculate a b = calculateSomething a b

也许可以通过拥有一个 嵌套模块 来进一步缩小 calculateSomething 的范围。

3
使用单元测试框架来测试私有方法可能是有道理的。不,这不是正确的做法:https://dev59.com/hnNA5IYBdhLWcg3wGJwV#1093481 - Mark Seemann
3个回答

4

如果您感觉您的代码太复杂,无法从外部测试它,请使用后一种选项。如果您想要测试内部函数,则可以使用以下方法:

let myComplicatedOperation input = 
    let calculateSomething a b =
        a + b
    calculateSomething (fst input) (snd input)

你总是可以像这样使用柯里化来重写它:

let myComplicatedOperation calculateSomething input =
    calculateSomething (fst input) (snd input)

尽管如此,您的问题似乎与F#没有直接关系。通常测试私有方法的一般方法是通过提取一个类(或者,在F#中,您也可以只提取一个let绑定函数),并在该其他类/函数上公开您的测试对象。


3

你可以使用即席接口来调用私有方法。

例如,我测试函数calcNodeLabel,位于https://code.google.com/p/fseye/source/browse/trunk/FsEye/Forms/WatchTreeView.fs#73,测试方法如下:https://code.google.com/p/fseye/source/browse/trunk/Test.FsEye/WatchTreeViewLabelCalculatorTests.fs#54

但是需要注意,在F#中测试隐藏的函数需要小心:它是编译器实现细节的一部分,函数实际上将如何被编译(例如作为方法、委托等)由编译器决定。

人们通常会警告不要测试私有方法,但我认为说“永远不要测试私有方法”有些简单化了。因为这种声明默认在.NET框架中指定的访问级别是唯一的方式,而事实并非如此。
例如,在我的示例中,calcNodeLabel确实应该隐藏起来不对外暴露,但我认为它是类的内部契约的一部分。当然,你可以争论类视图数据和视图本身应该分开,但是事实仍然存在:所有模型都是不完美的!

1
FYI,我正在弃用 ImpromptuInterface.FSharp,因为我已经用 PCL 版本 FSharp.Dynamic 替换了它,代码相同,命名空间不同,可以在 .NET4X / WinRT / Silverlight5 上使用。 - jbtule

3

我认为为了方便测试而放松类/模块中的访问限制通常是不好的。如果你已经决定某些内容对外部世界来说是无关紧要的,那么你想要测试它并不能使其变得更加重要。

难道你不能在类/模块中拥有一个公共方法/函数来执行测试吗?

type ThisClassIsComplicated () = 
    let calculateSomething a b =
        a + b 

    member private this.TestInstance () = 
        printfn "%A" <| calculateSomething 1 2

    static member Test () = 
        (new ThisClassIsComplicated()).TestInstance()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接