gpt4 book ai didi

f# - 自定义 FsCheck 输出

转载 作者:行者123 更新时间:2023-12-02 05:28:06 24 4
gpt4 key购买 nike

我正在 VisualStudio 中使用 FsCheck 和 NUnit 进行测试。

当前的问题是:我设法生成随机图(用于测试某些图功能),但是当测试失败时,FsCheck 会吐出整个图,并且它不使用 ToString,因此它实际上会转储原始记录列表,而您不能看到里面有什么。

此外,我不仅需要用于检查的输入图,还需要运行属性时创建的一些其他数据。

那么我如何更改 FsCheck 的输出行为以便

  • 实际在输入图上调用我的 ToString 方法
  • 输出更多信息

当测试失败时?

编辑:这是我当前的测试设置。

module GraphProperties

open NUnit.Framework
open FsCheck
open FsCheck.NUnit

let generateRandomGraph =
gen {
let graph: Graph<int,int> = Graph<_,_>.Empty()
// fill in random nodes and transitions...
return graph
}

type MyGenerators =
static member Graph() =
{new Arbitrary<Graph<int,int>>() with
override this.Generator = generateRandomGraph
override this.Shrinker _ = Seq.empty }

[<TestFixture>]
type NUnitTest() =
[<Property(Arbitrary=[|typeof<MyGenerators>|], QuietOnSuccess = true)>]
member __.cloningDoesNotChangeTheGraph (originalGraph: Graph<int,int>) =
let newGraph = clone originalGraph
newGraph = originalGraph

最佳答案

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 format 声明,因此 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 获得“给我一个函数来格式化失败的测试数据”配置参数之前,这是按照您需要的方式格式化测试数据的最佳方法。

关于f# - 自定义 FsCheck 输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45444084/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com