Functional programming 如何正确通过FsCheck测试

Functional programming 如何正确通过FsCheck测试,functional-programming,f#,fscheck,Functional Programming,F#,Fscheck,我有这样一个功能来检查列表的格式是否正确。列表不应包含空字符串和空值。由于Check.Verbose list返回可伪造的输出,因此我无法获取缺少的内容 我该如何处理这个问题?我想你还不太了解FsCheck。在执行Check.Verbose someFunction时,FsCheck会为函数生成一组随机输入,如果函数返回false,则会失败。其思想是,传递给Check.Verbose的函数应该是一个属性,无论输入是什么,该属性都将始终为true。例如,如果将列表反转两次,则无论原始列表是什么,它

我有这样一个功能来检查列表的格式是否正确。列表不应包含空字符串和空值。由于
Check.Verbose list
返回可伪造的输出,因此我无法获取缺少的内容


我该如何处理这个问题?

我想你还不太了解FsCheck。在执行
Check.Verbose someFunction
时,FsCheck会为函数生成一组随机输入,如果函数返回false,则会失败。其思想是,传递给Check.Verbose的函数应该是一个属性,无论输入是什么,该属性都将始终为true。例如,如果将列表反转两次,则无论原始列表是什么,它都应返回原始列表。该属性通常表示为:

let list p = if List.contains " " p || List.contains null p then false else true
另一方面,您的函数是一个好的、有用的函数,用于检查数据模型中的列表是否格式良好。。。但从某种意义上讲,它不是FsCheck使用的一个属性(也就是说,无论输入是什么,函数都应该返回true)。要创建FsCheck样式属性,您需要编写一个通常如下所示的函数:

let revTwiceIsSameList (lst : int list) =
    List.rev (List.rev lst) = lst

Check.Verbose revTwiceIsSameList  // This will pass
(请注意,我将您的函数命名为
myFunc
,而不是
list
,因为作为一般规则,您不应该将函数命名为
list
。名称
list
是一种数据类型(例如,
字符串列表
int列表
),如果你给一个函数命名
列表
,当同一个名字有两种不同的含义时,你只会把自己弄糊涂。)

现在,这里的问题是:如何编写我的
verifyMyFunc
示例中的“输入格式良好”部分?你不能仅仅用你的函数来检查它,因为那将是对你的函数本身进行测试,这不是一个有用的测试。(测试本质上会变成“myFunc input=myFunc input”,即使函数中有bug,它也会始终返回true——当然,除非函数返回随机输入)。因此,您必须编写另一个函数来检查输入是否格式正确,这里的问题是,您编写的函数是检查格式正确输入的最佳、最正确的方法。如果您编写了另一个要检查的函数,那么最终它将归结为
not(List.contains”“| | List.contains null)
,而且,您实际上是在对照函数本身检查函数


在这种情况下,我不认为FsCheck是适合这项工作的工具,因为您的功能非常简单。这是一个家庭作业吗?老师要求你使用FsCheck?或者你是想自己学习FsCheck,并通过这个练习自学FsCheck?如果是前者,那么我建议你的导师指出这个问题,看看他对我的答案怎么说。如果是后者,那么我建议找一些稍微复杂一点的函数来学习FsCheck。这里有一个有用的函数,您可以在其中找到一些应该始终为真的属性,如
List.rev
示例(将列表反转两次应该会恢复原始列表,因此这是一个有用的属性来测试)。或者,如果您在查找always true属性时遇到困难,请至少找到一个可以用至少两种不同方式实现的函数,这样您就可以使用FsCheck检查两种实现是否对任何给定输入返回相同的结果。

我想您还不太了解FsCheck。在执行
Check.Verbose someFunction
时,FsCheck会为函数生成一组随机输入,如果函数返回false,则会失败。其思想是,传递给Check.Verbose的函数应该是一个属性,无论输入是什么,该属性都将始终为true。例如,如果将列表反转两次,则无论原始列表是什么,它都应返回原始列表。该属性通常表示为:

let list p = if List.contains " " p || List.contains null p then false else true
另一方面,您的函数是一个好的、有用的函数,用于检查数据模型中的列表是否格式良好。。。但从某种意义上讲,它不是FsCheck使用的一个属性(也就是说,无论输入是什么,函数都应该返回true)。要创建FsCheck样式属性,您需要编写一个通常如下所示的函数:

let revTwiceIsSameList (lst : int list) =
    List.rev (List.rev lst) = lst

Check.Verbose revTwiceIsSameList  // This will pass
(请注意,我将您的函数命名为
myFunc
,而不是
list
,因为作为一般规则,您不应该将函数命名为
list
。名称
list
是一种数据类型(例如,
字符串列表
int列表
),如果你给一个函数命名
列表
,当同一个名字有两种不同的含义时,你只会把自己弄糊涂。)

现在,这里的问题是:如何编写我的
verifyMyFunc
示例中的“输入格式良好”部分?你不能仅仅用你的函数来检查它,因为那将是对你的函数本身进行测试,这不是一个有用的测试。(测试本质上会变成“myFunc input=myFunc input”,即使函数中有bug,它也会始终返回true——当然,除非函数返回随机输入)。因此,您必须编写另一个函数来检查输入是否格式正确,这里的问题是,您编写的函数是检查格式正确输入的最佳、最正确的方法。如果您编写了另一个要检查的函数,那么最终它将归结为
not(List.contains”“| | List.contains null)
,而且,您实际上是在对照函数本身检查函数

在这种情况下,我不认为FsCheck是适合这项工作的工具,因为您的功能非常简单。这是一个家庭作业吗?老师要求你使用FsCheck?或者你是想自己学习FsCheck,并通过这个练习自学FsCheck?如果是
let myFuncConcatenation l1 l2 = myFunc (l1 @ l2) = (myFunc l1 && myFunc l2)
FsCheck.Verbose myFuncConcatenation
0:
["X"]
["^"; ""]
1:
["C"; ""; "M"]
[]
2:
[""; ""; ""]
[""; null; ""; ""]
3:
...
Ok, passed 100 tests.
let myFuncHasNulls l = if List.contains null l then myFunc l = false else true
let myFuncHasEmpty l = if List.contains ""   l then myFunc l = false else true

Check.Quick myFuncHasNulls
Check.Quick myFuncHasEmpty

// Ok, passed 100 tests.
// Ok, passed 100 tests.