FsCheck 用于sprintf "%A"
将测试参数转换为测试输出中的字符串,因此您需要做的是控制格式化程序如何格式化您的类型%A
。根据如何使用 printf 自定义自定义类型的输出?,做到这一点的方法是使用StructuredFormatDisplay
属性。该属性的值应该是格式中的字符串PreText {PropertyName} PostText
,其中PropertyName
应该是您的类型的属性(而不是函数!)。例如,假设您有一个树结构,其中叶子中有一些复杂的信息,但是对于您的测试,您只需要知道叶子的数量,而不是叶子中的内容。所以你会从这样的数据类型开始:
// Example 1
type ComplicatedRecord = { ... }
type Tree =
| Leaf of ComplicatedRecord
| Node of Tree list
with
member x.LeafCount =
match x with
| Leaf _ -> 1
| Node leaves -> leaves |> List.sumBy (fun x -> x.LeafCount)
override x.ToString() =
// For test output, we don't care about leaf data, just count
match x with
| Leaf -> "Tree with a total of 1 leaf"
| Node -> sprintf "Tree with a total of %d leaves" x.LeafCount
现在,到目前为止,这不是你想要的。此类型没有声明自定义%A
格式,因此 FsCheck(以及sprintf "%A"
用于格式化它的任何其他内容)最终将输出树的整个复杂结构及其所有与测试无关的叶数据。要使 FsCheck 输出您想看到的内容,您需要设置一个属性,而不是一个函数(ToString
不会为此目的工作),它将输出您想看到的内容。例如:
// Example 2
type ComplicatedRecord = { ... }
[<StructuredFormatDisplay("{LeafCountAsString}")>]
type Tree =
| Leaf of ComplicatedRecord
| Node of Tree list
with
member x.LeafCount =
match x with
| Leaf _ -> 1
| Node leaves -> leaves |> List.sumBy (fun x -> x.LeafCount)
member x.LeafCountAsString = x.ToString()
override x.ToString() =
// For test output, we don't care about leaf data, just count
match x with
| Leaf -> "Tree with a total of 1 leaf"
| Node -> sprintf "Tree with a total of %d leaves" x.LeafCount
注意:我没有在 F# 中对此进行测试,只是将它输入到 Stack Overflow 评论框中——所以我可能搞砸了这ToString()
部分。(我不记得了,也无法通过快速谷歌找到,覆盖应该在with
关键字之后还是之前)。但我知道该StructuredFormatDisplay
属性是您想要的,因为我自己使用它来从 FsCheck 中获取自定义输出。
顺便说一句,您也可以StructuredFormatDisplay
在我的示例中为复杂的记录类型设置一个属性。例如,如果你有一个关心树结构而不关心叶子内容的测试,你可以这样写:
// Example 3
[<StructuredFormatDisplay("LeafRecord")>] // Note no {} and no property
type ComplicatedRecord = { ... }
type Tree =
| Leaf of ComplicatedRecord
| Node of Tree list
with
member x.LeafCount =
match x with
| Leaf _ -> 1
| Node leaves -> leaves |> List.sumBy (fun x -> x.LeafCount)
override x.ToString() =
// For test output, we don't care about leaf data, just count
match x with
| Leaf -> "Tree with a total of 1 leaf"
| Node -> sprintf "Tree with a total of %d leaves" x.LeafCount
现在,您的所有ComplicatedRecord
实例,无论其内容如何,都将LeafRecord
在您的输出中显示为文本,并且您将能够更好地专注于树结构——并且无需在类型上设置StructuredFormatDisplay
属性。Tree
这不是一个完全理想的解决方案,因为您可能需要根据StructuredFormatDisplay
您正在运行的各种测试的需要不时调整属性。(对于某些测试,您可能希望专注于叶子数据的一部分,对于其他测试,您可能希望完全忽略叶子数据,等等)。而且您可能希望在投入生产之前删除该属性。但在 FsCheck 获得“给我一个函数来格式化失败的测试数据”配置参数之前,这是让你的测试数据按照你需要的方式格式化的最佳方式。