2017-10-19 82 views
3

FsCheck有一些整洁的默认Arbitrary类型来生成测试数据。但是如果我的测试日期之一取决于另一个呢?FsCheck:如何生成依赖于其他测试数据的测试数据?

例如,考虑使获得的子永远不能比输入的字符串长的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会生成的时间比基因处理NonEmptyString长,导致异常。

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

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

如何让FsCheck只生成不超过输入字符串的PositiveInt?我相信我必须使用Gen<T>类,但它的接口只是海拉混乱,我...我尝试以下,但仍然有PositiveInt小号超过字符串:

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(); 
+0

https://fscheck.github.io/FsCheck/TestData.html – MethodMan

+0

我通过这个网站看起来已经多次,还是没能想出一个办法做我想做什么。 –

回答

4

您可以创建依赖于值发电机从另一个使用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); 
+0

这是我可以在[官方文档](https://fscheck.github.io/FsCheck/TestData.html)中找到的东西吗?如果不是,你可以添加你的参考吗? –

+2

@GoodNightNerdPride--我不认为我已经看到过很多关于C#interop的文档,所以我可能发现基于阅读“gen”构建器的源代码和受过教育的猜测。 F#计算表达式(如'gen {...}')与C#LINQ查询语法非常接近,因为它们是使用相同的语法模式构建的(尽管F#支持更多功能)。 – Lee

+1

对于F#计算表达式或LINQ语法,文档中没有太多示例。下面是一个示例https://github.com/fscheck/FsCheck/blob/master/examples/FsCheck.CSharpExamples/Program.cs#L150 LINQ在TestData页面的第二段中提到,这里有一个小例子: https://fscheck.github.io/FsCheck/TestData.html#Generators –