Ben*_*jol 13 f# unit-testing fscheck property-based-testing
我已经设法让xUnit处理我的小样本组件.现在我想知道我是否也可以参加FsCheck.我的问题是,在为我的函数定义测试属性时,我很难过.
也许我只是没有一套好的样本函数,但是这些函数的测试属性是什么呢?
//transforms [1;2;3;4] into [(1,2);(3,4)]
pairs : 'a list -> ('a * 'a) list //'
//splits list into list of lists when predicate returns
// true for adjacent elements
splitOn : ('a -> 'a -> bool) -> 'a list -> 'a list list
//returns true if snd is bigger
sndBigger : ('a * 'a) -> bool (requires comparison)
Run Code Online (Sandbox Code Playgroud)
Kur*_*out 14
已经有很多具体的答案,所以我会尝试给出一些可能给你一些想法的一般答案.
作为一般建议,尽量不要做太大的交易.对于sndBigger来说,一个好的财产将是:
当且仅当snd更大时,```应该返回true``(a:int)(b:int)= sndBigger(a,b)= b> a
这可能就是实施.不要担心 - 有时一个简单的,老式的单元测试正是你需要的.无需内疚!:)
也许这个链接 (由Pex团队提供)也提供了一些想法.
Tom*_*cek 10
我将从sndBigger- 它是一个非常简单的函数,但你可以编写一些应该保留它的属性.例如,当您反转元组中的值时会发生什么:
// Reversing values of the tuple negates the result
let swap (a, b) = (b, a)
let prop_sndBiggerSwap x =
sndBigger x = not (sndBigger (swap x))
// If two elements of the tuple are same, it should give 'false'
let prop_sndBiggerEq a =
sndBigger (a, a) = false
Run Code Online (Sandbox Code Playgroud)
编辑:此规则prop_sndBiggerSwap并不总是成立(请参阅kvb的评论).但是以下内容应该是正确的:
// Reversing values of the tuple negates the result
let prop_sndBiggerSwap a b =
if a <> b then
let x = (a, b)
sndBigger x = not (sndBigger (swap x))
Run Code Online (Sandbox Code Playgroud)
关于pairs功能,kvb已经发布了一些好主意.此外,您可以检查将转换后的列表转换回元素列表会返回原始列表(当输入列表为奇数时,您需要处理这种情况 - 取决于pairs函数在这种情况下应该执行的操作):
let prop_pairsEq (x:_ list) =
if (x.Length%2 = 0) then
x |> pairs |> List.collect (fun (a, b) -> [a; b]) = x
else true
Run Code Online (Sandbox Code Playgroud)
因为splitOn,我们可以测试类似的东西 - 如果你连接所有返回的列表,它应该给出原始列表(这不会验证分裂行为,但它开始是一件好事 - 它至少保证没有元素将迷路了.
let prop_splitOnEq f x =
x |> splitOn f |> List.concat = x
Run Code Online (Sandbox Code Playgroud)
我不确定FsCheck是否可以处理这个(!),因为该属性将函数作为参数(因此它需要生成"随机函数").如果这不起作用,您需要提供一些具有一些手写功能的特定属性f.接下来,实现f对分割列表中的所有相邻对返回true 的检查(如kvb所示)实际上并不困难:
let prop_splitOnAdjacentTrue f x =
x |> splitOn f
|> List.forall (fun l ->
l |> Seq.pairwise
|> Seq.forall (fun (a, b) -> f a b))
Run Code Online (Sandbox Code Playgroud)
可能你可以检查的唯一最后一件事就是当你给它一个列表中的最后一个元素和下一个列表中的第一个元素时f返回false.以下内容尚未完全完成,但它显示了要走的路:
let prop_splitOnOtherFalse f x =
x |> splitOn f
|> Seq.pairwise
|> Seq.forall (fun (a, b) -> lastElement a = firstElement b)
Run Code Online (Sandbox Code Playgroud)
最后一个示例还显示您应该检查splitOn函数是否可以返回空列表作为返回结果列表的一部分(因为在这种情况下,您找不到第一个/最后一个元素).
对于某些代码(例如sndBigger),实现非常简单,任何属性都至少与原始代码一样复杂,因此通过FsCheck进行测试可能没有意义.但是,对于其他两个函数,这里有一些你可以检查的东西:
pairs
List.map fst (pairs x) = evenEntries x和List.map snd (pairs x) = oddEntries x一些简单的功能evenEntries和oddEntries它你可以写.splitOn
splitOn f l,没有两个连续的条目满足f"和" (l1,l2)从splitOn f l成对中取出列表,f (last l1) (first l2)保持".不幸的是,这里的逻辑可能在复杂性上与实现本身相当.