我正在用FsCheck和NUnit测试VisualStudio。
目前的问题是:我成功地生成了随机图(用于测试一些图形功能),但是当测试失败时,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发布于 2017-08-02 07:03:03
FsCheck使用sprintf "%A"将测试参数转换为测试输出中的字符串,因此您需要做的是控制%A格式化程序如何格式化您的类型。根据How do I customize output of a custom type using printf?的说法,实现这一目标的方法是使用 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"格式化它的东西)最终都会输出整个复杂的树结构及其所有无关的叶数据。要使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#中测试这一点,只是在堆栈溢出注释框中输入了它--所以我有可能把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获得一个配置参数“给我一个函数来格式化失败的测试数据”之前,这是按照您需要的方式格式化测试数据的最佳方法。
发布于 2017-08-18 22:05:34
当测试失败时,您也可以使用标签来显示您想要的任何内容:https://fscheck.github.io/FsCheck/Properties.html#And-Or-and-Labels
https://stackoverflow.com/questions/45444084
复制相似问题