我正在使用VisualStudio中的FsCheck和NUnit进行测试。
目前的问题是:我设法生成随机图(用于测试一些图形功能)但是当测试失败时,FsCheck吐出整个图形并且它不使用ToString所以它实际上转储原始记录列表而你不能看到那里的任何东西。
此外,我不仅需要输入图表进行检查,还需要在运行属性时创建的其他一些数据。
那么我怎么能改变FsCheck的输出行为才能
测试失败时?
编辑: 这是我目前的测试设置。
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
答案 0 :(得分:1)
FsCheck使用sprintf "%A"
将测试参数转换为测试输出中的字符串,因此您需要做的是控制%A
格式化程序对您的类型的格式化方式。根据{{3}},使用How do I customize output of a custom type using printf?的方法是这样做的。该属性的值应为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
将无法用于此目的),它将输出您想要的内容查看。 E.g:
// 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
,您将能够更好地专注于树结构 - 而且无需在StructuredFormatDisplay
类型上设置Tree
属性。
这不是一个完全理想的解决方案,因为您可能需要根据您正在运行的各种测试的需要不时调整StructuredFormatDisplay
属性。 (对于某些测试,您可能希望关注叶子数据的一部分,对于其他人,您要完全忽略叶子数据,依此类推)。在开始制作之前,您可能想要取出该属性。但是直到FsCheck收到“给我一个使用config参数格式化失败的测试数据的功能”,这是以你需要的方式格式化测试数据的最好方法。
答案 1 :(得分:0)
您还可以使用标签在测试失败时显示您想要的任何内容:https://fscheck.github.io/FsCheck/Properties.html#And-Or-and-Labels