如何在 QuickCeck 中使用 shuffle 生成测试数据

How to generate test data with shuffle in QuickCeck

对于给定列表 [1..n],其中 n 是一个随机正整数,我想通过 2 个步骤生成测试数据:

  1. 随机播放列表,xs = 随机播放 [1..n];
  2. 将 xs 中的数字 x 随机变异为 y,其中 1 <= y <= n;

经过这两个步骤后,新列表表示为 ys。

我写了一个程序。它接受ys,输出(x, y),函数原型是这样的:

solve :: [a] -> (a, a)

我想使用 Test.QuickCheck 来测试我的程序。如何生成这样的测试数据?我看到 QuickCheck

中有一个函数
shuffle :: [a] -> Gen [a]

但是不知道怎么用

QuickCheck 中的 Gen monad 基本上是一个以随机数生成器作为其状态的状态 monad。所以当你看到

shuffle :: [a] -> Gen [a]

这意味着这个参数接受一个列表和 returns 一个随机列表 "in" Gen monad。

因为它是一个 monad,所以您可以将它放在 do 子句中。不太清楚你的要求,但我认为它是这样的:

myTest :: Integer -> Gen [Integer]
myTest 0 = return []
myTest n = do
   ns <- shuffle [1..n]
   x <- choose (0,n-1)
   y <- choose (1,n)
   let (ns1,ns2) = splitAt x ns
   return $ ns1 ++ [y] ++ drop 1 ns2`

您可以使用 generate 在 Gen monad 中 运行 一个动作,其中 returns 是 IO 中的一个值,或者您可以为您的测试数据并使其成为 Arbitrary 的实例,其中包含函数

arbitrary :: Gen a

编辑: 或者正如 Zeta 在评论中指出的那样,您可以使用 forAll:

quickCheck $ forAll (myTest 10) $ \x -> ....