如何在 QuickCeck 中使用 shuffle 生成测试数据
How to generate test data with shuffle in QuickCeck
对于给定列表 [1..n],其中 n 是一个随机正整数,我想通过 2 个步骤生成测试数据:
- 随机播放列表,xs = 随机播放 [1..n];
- 将 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 -> ....
对于给定列表 [1..n],其中 n 是一个随机正整数,我想通过 2 个步骤生成测试数据:
- 随机播放列表,xs = 随机播放 [1..n];
- 将 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 -> ....