unit-testing - 对F#中的高阶函数进行单元测试

标签 unit-testing f# functional-programming higher-order-functions

以下面的F#示例为例:

let parse mapDate mapLevel mapMessge (groups : string list) = 
    {
        DateTime = 
            mapDate(
                groups.[2] |> Int32.Parse, 
                groups.[0] |> Int32.Parse, 
                groups.[1] |> Int32.Parse)
        Level = mapLevel groups.[3]
        Message = mapMessge  groups.[4]
    }

我可以独立地对map函数进行单元测试,但是如何对这个函数正确调用作为参数传入的函数进行单元测试?

在C#中,我将使用模拟并验证对它们的调用。我最近看了一个多元视力视频,该视频讨论了功能语言如何倾向于使用 stub 而不是模拟。在这里,我可以传递一个函数,如果它没有获得预期的参数,则抛出该函数,但是这种方法并没有真正让我满意。

我只是想知道函数式编程中是否有任何模式可以对这样的高阶函数进行单元测试?

最佳答案

好吧,让我不同意给出的答案。实际上,有一种很好的方法可以测试高阶函数,而不必理会它们可能采用的具体类型(我认为典型的HOF是完全通用的,但是没有区别:我建议的方法将正确地适用于更严格的HFO)。

让我们来做一个非常简单的事情,每个人都熟悉的事情。 ['t] -> ['t]函数如何?它只接受一个参数-列表(无论类型如何),并返回相同类型的列表。传统的OOP方法在这里行不通:需要限制't并测试该类型的某些特定参数; 唯一的方式可以使作者对其实现更有信心,这是增加单元测试的数量。

在数学中确实有很棒的东西叫做“范畴论”。它是一个相对较新的数学领域,它从外部而不是内部研究事物。为了能够从外部描述事物,您需要采取自己感兴趣的事物,并使其与您已经足够了解的事物进行交互。因此,范畴论教导了用事物与其他事物的相互关系来描述事物。我们不能在这里做同样的事情吗?

确实,我们可以。这实际上很容易:我们已经有了一个f : ['t] -> ['t],但是还有什么其他方法可以使我们既可以交互又可以定义公用的东西-每个交互都可以保留的东西,而不受任何其他因素的影响?让我们将用作任何 g: 't -> 'y。现在我们可以声明:g (List.head (f ...) = List.head (List.map g (f ...))。我假设使用['t]类型的某个参数来替代...。请注意:给定的属性是通用的:指定签名的任何纯函数组成都将适用,而不论其实现如何。还要注意,它是多么通用但很明显:只有两个截然不同的“对象”通过“组成”相互交互,这也可以根据标准F#的(|>), (<|)运算符进行重写。

现在的事实是,对于任何
高阶(纯)函数,都存在这种通用属性。大多数情况下,有数十种。因此,一个能够根据组成(对于FP而言是常规的)指定其属性的属性就停留在通用级别上。以显式形式具有这样的属性,不仅可以根据输入值(其值通常由单元测试完成,但很少会自动生成,但也不同)进行输入,从而有机会自动生成数百个测试。

关于unit-testing - 对F#中的高阶函数进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42892313/

相关文章:

rust - 为什么我得到 FromIterator<&T>` is not Implemented for Vec<T>?

c# - 为具有 protected 对象 C# 的代码编写单元测试的好方法是什么(使用 NMock 和 NUnit 框架)

java - 使用 iText 为生成的 PDF 创建单元测试

f# - 范围A到B,其中F#中的A> B

visual-studio - Visual Studio for F# 中的代码折叠

f# - 通过任务选择在目标中生成的 ItemGroup 文件的位置

python - 单元测试通过了 Django 中模型的正则表达式验证器

c# - 测试 WebApi Controller Url.Link

algorithm - Haskell求两个最近点之间的距离

.net - 选择是否对 F# 中的小型 AST 使用可区分联合或记录类型