6

FsCheck 有一些简洁的默认Arbitrary类型来生成测试数据。但是,如果我的一个考试日期取决于另一个考试日期怎么办?

例如,考虑string.Substring()结果子字符串永远不能长于输入字符串的属性:

[Fact]
public void SubstringIsNeverLongerThanInputString()
{
    Prop.ForAll(
        Arb.Default.NonEmptyString(),
        Arb.Default.PositiveInt(),
        (input, length) => input.Get.Substring(0, length.Get).Length <= input.Get.Length
    ).QuickCheckThrowOnFailure();
}

虽然实现Substring肯定是正确的,但这个属性失败了,因为最终PositiveInt会生成比生成的更长的 a,NonEmptyString从而导致异常。

收缩:NonEmptyString "a" PositiveInt 2 异常:System.ArgumentOutOfRangeException:索引和长度必须引用字符串中的位置。

我可以与 an 进行比较,if (input.Length < length) return true;但这样我最终会进行大量测试运行,甚至没有检查该属性。

如何告诉 FsCheck 只生成PositiveInt不超过输入字符串的 s?我想我必须使用这个Gen<T>类,但它的界面让我很困惑......我尝试了以下但仍然PositiveInts 超过了字符串:

var inputs = Arb.Default.NonEmptyString();
// I have no idea what I'm doing here...
var lengths = inputs.Generator.Select(s => s.Get.Length).ToArbitrary();

Prop.ForAll(
    inputs,
    lengths,
    (input, length) => input.Get.Substring(0, length).Length <= input.Get.Length
).QuickCheckThrowOnFailure();
4

1 回答 1

7

您可以创建依赖于从另一个使用生成的值的生成器SelectMany。这也允许您使用 LINQ 查询语法,例如

var gen = from s in Arb.Generate<NonEmptyString>()
          from i in Gen.Choose(0, s.Get.Length - 1)
          select Tuple.Create(s, i);

var p = Prop.ForAll(Arb.From(gen), t =>
{
    var s = t.Item1.Get;
    var len = t.Item2;
    return s.Substring(0, len).Length <= s.Length;
});

Check.Quick(p);
于 2017-10-19T18:25:21.837 回答