如何覆盖 FsCheck 中所有属性的字符串生成
How to override string generation for all properties in FsCheck
我有一堆到处都是字符串的类型。我想使用 FsCheck 为在这些类型上运行的函数编写 属性 测试。对于所有这些,我知道我永远不会得到空字符串或非字母数字字符串。
因此,我想相应地限制字符串的值生成。
我试过这个:
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 = "6z^k";} (At least one control character has been escaped as a char code, e.g. 3)
Shrunk:
{LeftLanguageName = "
";
RightLanguageName = "";}
很明显我遗漏了什么,但我不知道是什么。
我看了
How to generate null strings for FsCheck tests
和
http://blog.nikosbaxevanis.com/2015/09/25/regex-constrained-strings-with-fscheck/
但它们都没有尝试覆盖字符串生成全局(在范围内)。
我无法重现该问题。使用 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
值作为您的长度,然后在循环中从允许的字符集中生成一个字符,然后然后连接这些字符(这给你 只有 有效字符串)。
我有一堆到处都是字符串的类型。我想使用 FsCheck 为在这些类型上运行的函数编写 属性 测试。对于所有这些,我知道我永远不会得到空字符串或非字母数字字符串。 因此,我想相应地限制字符串的值生成。
我试过这个:
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 = "6z^k";} (At least one control character has been escaped as a char code, e.g. 3)
Shrunk:
{LeftLanguageName = "
";
RightLanguageName = "";}
很明显我遗漏了什么,但我不知道是什么。
我看了
How to generate null strings for FsCheck tests
和
http://blog.nikosbaxevanis.com/2015/09/25/regex-constrained-strings-with-fscheck/
但它们都没有尝试覆盖字符串生成全局(在范围内)。
我无法重现该问题。使用 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
值作为您的长度,然后在循环中从允许的字符集中生成一个字符,然后然后连接这些字符(这给你 只有 有效字符串)。