FsCheck 使用sprintf "%A" 将测试参数转换为测试输出中的字符串,因此您需要做的是控制%A 格式化程序如何格式化您的类型。根据How do I customize output of a custom type using printf?,方法是使用StructuredFormatDisplay attribute。该属性的值应该是格式为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" 对其进行格式化的东西)最终会输出树的整个复杂结构及其所有不相关的-to-the-test 叶数据。要让 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() 部分。 (我不记得,也无法通过快速的 Google 找到,覆盖应该在 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,您将能够更好地专注于树形结构——而且没有必要在Tree 类型上设置StructuredFormatDisplay 属性。
这不是一个完全理想的解决方案,因为您可能需要根据正在运行的各种测试的需要不时调整StructuredFormatDisplay 属性。 (对于某些测试,您可能希望关注叶子数据的一部分,对于其他测试,您可能希望完全忽略叶子数据,等等)。而且您可能希望在投入生产之前删除该属性。但在 FsCheck 获得“Give me a function to format failed test data with”配置参数之前,这是让您的测试数据按照您需要的方式格式化的最佳方式。