【问题标题】:unit test private methods in F#F# 中的单元测试私有方法
【发布时间】:2014-03-18 11:46:21
【问题描述】:

假设我们有一个类

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

在这种情况下,calculateSomething 是微不足道的,但如果它会更复杂,那么验证那里所做的计算是否正确可能是有意义的。

使用unit testing framework 来测试私有方法可能是有意义的。

我的问题:如何在 F# 中对私有方法进行单元测试?

一些随意的想法:

选择的答案here,建议使用InternalsVisibleTo attribute,无论如何它只适用于internalmethods

如果有的话,特定于 F# 的路由是什么?这在 F# 设计中更好吗?

let calculateSomething a b = a + b 

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

也许calculateSomething 的范围甚至可以通过nested module 来缩小。

【问题讨论】:

标签: unit-testing f# private-members


【解决方案1】:

如果您觉得您的代码过于复杂而无法从外部进行测试,请使用后一种选项。如果你想测试一个内部函数,比如

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 绑定函数)。并让您的测试对象在其他类/函数上公开。

【讨论】:

    【解决方案2】:

    我认为放松类/模块中的访问限制以促进测试通常是一个坏主意。如果你已经决定某些东西对于外界来说是无关紧要的,你想要测试它并不会让它变得无关紧要。

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

    type ThisClassIsComplicated () = 
        let calculateSomething a b =
            a + b 
    
        member private this.TestInstance () = 
            printfn "%A" <| calculateSomething 1 2
    
        static member Test () = 
            (new ThisClassIsComplicated()).TestInstance()
    

    【讨论】:

      【解决方案3】:

      您可以使用Impromptu Interface 调用私有方法。

      例如,我测试函数calcNodeLabel at 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# 中测试 hidden 函数:它是 编译器 函数的实际编译方式的实现细节(例如,作为方法,作为代表,作为...)。

      人们通常会警告不要测试私有方法,但我认为说“从不测试私有方法”有点简单,因为这样的声明理所当然地认为 .NET 框架中指定的访问级别是唯一的方法他们可能是。

      例如,calcNodeLabel 在我的示例中确实应该对广阔的世界隐藏,但我会认为它是班级内部契约的一部分。当然,你可以争辩说类视图数据和视图本身应该分开,但重点是:所有模型都是不完美的!

      【讨论】:

      • 仅供参考,我正在弃用 ImpromptuInterface.FSharp,因为我已将其替换为 PCL 版本 FSharp.Dynamic,相同的代码、不同的命名空间并适用于 .NET4X/WinRT/Silverlight5
      猜你喜欢
      • 2014-08-10
      • 1970-01-01
      • 1970-01-01
      • 2013-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多