如何在Haskell中结合quickCheckAll与size约束执行批量测试
结合quickCheckAll与size约束批量运行QuickCheck测试
我需要用quickCheckAll批量运行多个QuickCheck测试,同时给这些测试指定size约束。当前的Haskell程序中有两个测试,不加size约束的话很难正常执行:
- 计算大整数的所有分划会超出算法算力
- 测试随机正整数列表时会丢弃大量无效列表
原程序代码如下:
{-# LANGUAGE TemplateHaskell #-} module Partitions where import Test.QuickCheck import Test.QuickCheck.All import Data.List (sort) sizeCheck n = quickCheckWith (stdArgs {maxSize = n}) partitions :: Int -> [[Int]] partitions 0 = [[]] partitions n | n > 0 = [k:xs | k <- [1..n], xs <- partitions (n - k), all (k <=) xs] -- "adding up all of the numbers in each partition should give 𝑛" prop_partitions :: Int -> Property prop_partitions n = n >= 0 ==> all ((== n) . sum) (partitions n) -- "sorting any list of strictly positive integers gives one of the -- partitions of its sum" prop_partitions' :: [Int] -> Property prop_partitions' xs = all (>0) xs ==> sort xs `elem` partitions (sum xs) return [] runTests = $quickCheckAll
我平时的做法是通过TemplateHaskell编译指示、命名以prop_开头的Property类型测试,搭配return []和runTests = $quickCheckAll来批量运行所有测试。教材里提供了用quickCheckWith指定size约束的便捷方式sizeCheck n = quickCheckWith (stdArgs {maxSize = n}),但找不到把quickCheckAll和quickCheckWith结合的方法。我试过用$allProperties收集测试后用map搭配quickCheckWith,但没成功,也不想通过自定义arbitrary生成测试用例来绕路。
解决方案
可以直接利用$allProperties生成的测试列表,结合mapM_来为每个测试指定size约束。修改runTests函数,让它接受一个size参数,遍历所有测试并使用quickCheckWith执行:
return [] -- 接受size参数,批量运行所有带指定maxSize的测试 runTests :: Int -> IO () runTests n = mapM_ runSingleTest $allProperties where runSingleTest (testName, prop) = do putStrLn $ "Running test: " ++ testName quickCheckWith (stdArgs {maxSize = n}) prop
说明
$allProperties是Template Haskell自动生成的列表,每个元素是(String, Property)类型,对应测试名称和测试属性mapM_会遍历这个列表,对每个测试执行runSingleTest函数:先打印测试名称,再用指定maxSize的参数运行测试- 之前用
map失败是因为quickCheckWith返回的是IO动作,map只会生成[IO Result],不会执行这些动作,而mapM_会依次执行所有IO动作
这样就能批量运行所有prop_开头的测试,同时统一指定size约束,不需要修改测试用例的arbitrary实例。
内容的提问来源于stack exchange,提问作者Geoffrey Warne
相关产品推荐
相关产品推荐

