我到处都有一堆带有字符串的类型。我想使用FsCheck编写针对在这些类型上运行的函数的属性测试。对于所有这些,我知道我永远不会得到为null或非字母数字的字符串。 因此,我想相应地限制字符串的值生成。
我尝试过:
let charSet= "abc" // simplified for the example
let isValidString (s:string) = null<>s && not (s |> Seq.exists (fun c -> not (charSet |> Seq.contains c)))
let createConfig left right = {LeftLanguageName= left; RightLanguageName= right}
let generateString= Arb.generate<string> |> Gen.filter isValidString
let generateConfig= createConfig <!> generateString <*> generateString
type Generators =
static member String() =
{
new Arbitrary<string>() with
override x.Generator = generateString
}
static member LanguageConfiguration()=
{
new Arbitrary<LanguageConfiguration>() with
override x.Generator = generateConfig
}
Arb.register<Generators>() |> ignore
但是,FsCheck会不断生成这样的值
Falsifiable, after 14 tests (9 shrinks) (StdGen (2144073619,296598634)):
Original:
{LeftLanguageName = " 1c\J
";
RightLanguageName = "\026z^k";} (At least one control character has been escaped as a char code, e.g. \023)
Shrunk:
{LeftLanguageName = "
";
RightLanguageName = "";}
所以很明显我缺少了一些东西,但是我不知道是什么。
我看着
How to generate null strings for FsCheck tests
和
http://blog.nikosbaxevanis.com/2015/09/25/regex-constrained-strings-with-fscheck/
,但是它们都没有尝试在全局范围内(在范围内)覆盖字符串生成。
答案 0 :(得分:2)
我无法重现该问题。使用FSCheck 2.14.0,我尝试在F#脚本文件中运行以下命令:
#r "C:/Temp/nuget/packages/fscheck/lib/net452/FsCheck.dll"
open FsCheck
type LanguageConfiguration =
{ LeftLanguageName:string; RightLanguageName:string }
let charSet= "abc" // simplified for the example
let isValidString (s:string) =
null<>s && not (s |> Seq.exists (fun c -> not (charSet |> Seq.contains c)))
let createConfig left right = {LeftLanguageName= left; RightLanguageName= right}
let generateString= Arb.generate<string> |> Gen.filter isValidString
let generateConfig= createConfig <!> generateString <*> generateString
type Generators =
static member String() =
{ new Arbitrary<string>() with
override x.Generator = generateString }
static member LanguageConfiguration()=
{ new Arbitrary<LanguageConfiguration>() with
override x.Generator = generateConfig }
Arb.register<Generators>() |> ignore
Check.QuickThrowOnFailure (fun (n:LanguageConfiguration) ->
printfn "%A" n
true)
这将运行100个测试,并且输出如下所示:
{LeftLanguageName = "";
RightLanguageName = "";}
{LeftLanguageName = "";
RightLanguageName = "";}
{LeftLanguageName = "";
RightLanguageName = "";}
{LeftLanguageName = "";
RightLanguageName = "";}
{LeftLanguageName = "";
RightLanguageName = "";}
这表明您的测试生成还有另一个问题(也许只是在这个简化的演示中),这是因为您的Gen.filter isValidString
调用基本上消除了所有有趣的输入,因为它们是无效的。
您可以通过不同方式生成字符串来解决此问题-更好的方法是生成一个int
值作为长度,然后在循环中从允许的字符集中生成一个字符,然后进行串联这些字符(只为您提供 有效字符串)。