【问题标题】:How to create a generator with a fixed list of items for FsCheck如何为 FsCheck 创建具有固定项目列表的生成器
【发布时间】:2017-04-25 05:17:18
【问题描述】:

我最初尝试创建一个固定前 5 个元素的生成器(并且在使用 Prop.forAll 的任何测试中,前五个元素总是会运行),但没有这样做。

现在我试图通过在一个范围内使用一个随机数据生成器和一个用于非随机数据(即固定序列)的生成器来简化这一点。它类似于Gen.constant,只是它不是一个值,而是一个值序列。

我有这个(简化的可重现示例,适用于 NUnit 和 xUnit):

[<Property(Verbose = true, MaxTest=5)>]
static member MultiplyIdentityCornerCases () =
    Gen.elements [0L; -1L; 1L; Int64.MinValue; Int64.MaxValue]
    |> Arb.fromGen 
    |> Prop.forAll <| fun x -> x = x * 1L

输出是(不知道null 来自哪里):

0:
<null>
9223372036854775807L
1:
<null>
-9223372036854775807L
2:
<null>
-9223372036854775807L
3:
<null>
1L
4:
<null>
-9223372036854775807L
Ok, passed 5 tests.

我希望输出包含序列中的所有五个测试,最好但不一定是按顺序排列。我知道我可以使用 testdata 提供程序使用 NUnit(或任何单元测试系统)来做到这一点,但我想知道我是否可以使用 FsCheck 来做到这一点(或者我是否应该这样做,也许这是一个坏主意)。

我认为使用 FsCheck 很有用,至于有多个函数参数的情况,我希望它能够详尽地测试我给它的所有极端情况参数的组合。这希望使用 FsCheck 比使用测试数据提供者更容易。

【问题讨论】:

  • 大声思考,解决这个问题的一种方法可能是使用数字生成器的非随机性(或检查它是如何完成的),对于整数,它似乎完全按照我需要的方式工作工作(参见我的earlier question 的 FsCheck 输出)

标签: random f# fscheck


【解决方案1】:

我不知道这是可能的,但你可以这样做:

open System
open FsCheck
open FsCheck.Xunit

[<Property>]
let MultiplyIdentityCornerCases () =
    Gen.oneof [
        Gen.elements [Int64.MinValue; -1L; 0L; 1L; Int64.MaxValue]
        Arb.generate ]
    |> Arb.fromGen
    |> Prop.forAll <| fun x -> x = x * 1L

两个生成器被传递给Gen.oneof,因此每个生成器将生成大约一半的值。

Gen.elements 应该从提供的序列中的所有值中统一选择,因此它将使用例如0L 20% 的时间,但仅适用于 Gen.oneof 使用 Gen.elements 的那一半。

换句话说,每个“特殊”值将在 50% * 20% = 10% 的时间内生成。

默认情况下,一个属性运行 100 个测试用例,因此平均而言,它应该生成 10 个0L 值、10 个Int64.MinValue 值,依此类推。这通常应该足够好。


如果不是,您总是可以这样做:

open System
open Xunit
open FsCheck
open FsCheck.Xunit
open Swensen.Unquote

[<Theory>]
[<InlineData(Int64.MinValue)>]
[<InlineData(-1L)>]
[<InlineData( 0L)>]
[<InlineData( 1L)>]
[<InlineData(Int64.MaxValue)>]
let MultiplyIdentityCornerCases x = x =! x * 1L

[<Property>]
let MultiplyIdentityCornerCasesProperty x =
    MultiplyIdentityCornerCases x

在这里,您使用 xUnit.net 的 [&lt;Theory&gt;] 功能定义了一个参数化测试,并将您关心的五个极端情况提供给它。当您运行测试时,测试运行器将运行这五个测试用例。

此外,它将运行MultiplyIdentityCornerCasesProperty,因为它带有[&lt;Property&gt;] 注释,并且该函数只是调用另一个函数。

【讨论】:

  • 我最喜欢第二个code-sn-p。它实际上非常整洁。
  • 再次感谢,马克。我喜欢第二种方法,前提是我可以替换数据提供者的静态数据,但这应该不是问题。现在我已经使用了您上面第一种方法的变体,它在实践中似乎工作正常(并确保运行足够的测试以确定所有概率)。
猜你喜欢
  • 1970-01-01
  • 2018-04-15
  • 2012-04-03
  • 1970-01-01
  • 1970-01-01
  • 2016-10-16
  • 1970-01-01
  • 2015-04-13
  • 2018-11-16
相关资源
最近更新 更多