使用FsCheck Haskell QuickCheck测试库的F#版本,从C#生成测试,我发现随机字符串生成器不会生成空字符串。
using FsCheck.Fluent;
Spec.ForAny<string>(s => s != null).QuickCheck(); // always pass
此外,似乎没有按设计处理空字符串,但我没有设法将其固定from the documentation。例如,只需在两个字符串之间进行选择,其中一个为null,就不起作用了:
var strings = Any.ValueIn<string>(null, "non-null string");
Spec.For(strings, s => true).QuickCheck(); // throws null ref exception
字符串似乎是一种特殊情况,因为它处理自定义对象,例如
class Thing {}
与空值混合时:
var objects = Any.ValueIn(null, new Thing());
Spec.For(objects, s => true).QuickCheck(); // pass
答案 0 :(得分:4)
我试图深入研究一下,看来你在FsCheck中发现了一个错误。
问题出现在文件Arbitrary.fs中,并且实际上只与字符串相关。我不得不替换它,他们在字符串上调用ToCharArray
static member String() =
{ new Arbitrary<string>() with
override x.Generator = Gen.map (fun chars -> new String(List.toArray chars)) generate
override x.Shrinker s = s.ToCharArray() |> Array.toList |> shrink |> Seq.map (fun chars -> new String(List.toArray chars))
}
用这个
static member String() =
{ new Arbitrary<string>() with
override x.Generator = Gen.map (fun chars -> new String(List.toArray chars)) generate
override x.Shrinker s =
match s with
| null -> seq {yield null;}
| _ -> s.ToCharArray() |> Array.toList |> shrink |> Seq.map (fun chars -> new String(List.toArray chars))
}
您可能希望使用fscheck开发人员here来提高这一点,并检查我的修复是否正常 - 可能有更好的方法来实现它,但对于已经知道代码的人来说会更简单。
答案 1 :(得分:1)
对于FsCheck 1.x,我找到了一个涉及修改默认随机字符串生成器的解决方案:
public class MyArbitraries
{
public static Arbitrary<string> String()
{
var nulls = Any.Value<string>(null);
var nonnulls = Arb.Default.String().Generator;
return Any.GeneratorIn(nulls, nonnulls).ToArbitrary;
}
}
然后用以下内容初始化:
DefaultArbitraries.Add<MyArbitraries>();
然后问题中的测试按预期失败:
Spec.ForAny<string>(s => s != null).QuickCheck() // now fails, which is good
这将产生大约50%的空值和50%的随机字符串,权重可以调整:
Spec.ForAny<string>(s => true)
.Classify(s => s==null, "null")
.Classify(s => s!=null, "not null")
.QuickCheck(); // displays percentages
但是,如果默认情况下不包含null值的决定是故意的而不是库中的错误,那么有效地覆盖默认字符串生成器可能不是一个好主意。并且,如果它是一个错误,它会在修复时扭曲分布。