如何通过FsCheck生成元组

时间:2018-01-02 10:32:13

标签: f# fscheck property-based-testing

这是json一代:

let strGen = Arb.Default.String()
                |> Arb.toGen
strGen
    |> Gen.arrayOf
    |> Gen.map (String.concat "\", \"")
    |> Gen.map (fun strs -> "[\"" + strs + "\"]")

如何在我的测试体中创建string json以确定最终结果。

2 个答案:

答案 0 :(得分:4)

我的原始答案是使用Gen.map2组合两个生成器,一个用于字符串数组,另一个用于json字符串。但是Gen.map2专门设计的让两个独立的生成器组合在一起,即一个生成器的结果不会影响另一个生成器的结果。 (例如,滚动两个骰子:第一个骰子的结果与第二个骰子的结果无关)。你需要的是一个简单的Gen.map,它接受​​字符串数组生成器并生成一个元组(字符串数组,json)。像这样:

let strGen = Arb.Default.String() |> Arb.toGen
let arrayGen = strGen |> Gen.arrayOf
arrayGen |> Gen.map (fun array ->
    let json =
        array
        |> String.concat "\", \""
        |> fun strs -> "[\"" + strs + "\"]")
    array,json)

不同于下面的组合两个独立生成器的答案,这里只有一个生成器,其值用于生成数组和json值。所以这些值将依赖而不是独立,并且json将始终匹配字符串数组。

原创,不正当,在下面回答,保留以防两个答案之间的对比有用:

  

易。只需保存数组生成器,稍后再使用它,使用Gen.map2组合数组和json。 E.g:

let strGen = Arb.Default.String()
                |> Arb.toGen
let arrayGen = strGen |> Gen.arrayOf
let jsonGen =
    arrayGen
    |> Gen.map (String.concat "\", \"")
    |> Gen.map (fun strs -> "[\"" + strs + "\"]")
Gen.map2 (fun array json -> array,json) arrayGen jsonGen
     

现在你有一个生成2元组的生成器。元组的第一个元素是字符串数组,第二个元素是生成的json。

     顺便说一下,你的JSON创建代码还不是很正确,因为如果生成的字符串包含引号,你需要以某种方式引用它们,否则生成的JSON将无效。但我会让你处理这个问题,或者如果你不知道如何处理这个问题就提出一个新的问题。 "单一责任原则"也适用于Stack Overflow问题:理想情况下,每个问题应该只涉及一个主题。

答案 1 :(得分:2)

似乎无法将代码放入评论中,所以这里是一个清理过的版本:

let isDigitOrWord i =
        i |> String.isNullOrEmpty 
        |> not && Regex.IsMatch(i,"^[a-zA-Z0-9 ]*$")

let strGen = Arb.Default.String() |> Arb.toGen

Gen.arrayOf strGen 
|> Gen.map (fun array ->
    let array = array |>  Array.filter isDigitOrWord
    let json =
        array
        |> String.concat "\", \"" 
        |> fun strs -> if strs|> String.isEmpty then strs else "\"" + strs + "\""
        |> fun strs -> "[" + strs + "]"
    array,json)