我是Haskell的新手。到目前为止它非常好,但我正在尝试复制粘贴我的QuickCheck属性,我想解决这个问题。
这是一个简单的例子:
prop_Myfunc :: [Int] -> (Int,Int) -> Bool
prop_Myfunc ints (i,j) = ints !! i == ints !! j
这不会起作用,因为QuickCheck生成负数,所以我得到了
*** Failed! (after 2 tests and 2 shrinks):
Exception:
Prelude.(!!): negative index
我试图谷歌寻求解决方案,我发现,例如NonNegative和==>,但我不了解它们是如何工作的。
如何限制上述示例,以便i和j永远不会消极?而且,既不是太高了?那就是:0 <= i,j < length ints
答案 0 :(得分:10)
首先,请参阅this SO answer,了解如何编写自定义Gen ...
函数以及如何使用forAll
组合器的示例。
以下是如何为列表中的非空列表和两个有效的非负索引编写生成器:
import Test.QuickCheck
genArgs :: Gen ( [Int], Int, Int )
genArgs = do
x <- arbitrary
xs <- arbitrary
let n = length xs
i <- choose (0,n)
j <- choose (0,n)
return ( (x:xs), i, j) -- return a non-empty list
test = quickCheck $ forAll genArgs $ \(xs,i,j) -> prop_myfunc xs (i,j)
答案 1 :(得分:5)
约束包装器(来自Test.QuickCheck.Modifiers
,如果它们没有被隐式重新导出)可以这样使用:
prop_Myfunc :: [Int] -> (NonNegative Int, NonNegative Int) -> Bool
prop_Myfunc ints (NonNegative i, NonNegative j) = ints !! i == ints !! j
您可以将SomeWrapper a
视为已修改分发的a
。例如,NonNegative a
可确保a >= 0
。在生成包装器之后,可以使用模式匹配或显式访问器(在这种情况下为getNonNegative
)获取值。
至于约束索引的上边距,我认为使用包装器是不可能的(在Haskkell类型系统中不可能参数化具有值的类型,在这种情况下列表长度)。但是,使用==>
运算符,您可以为测试添加任意布尔约束:
prop_Myfunc ints (NonNegative i, NonNegative j) = i < l && j < l ==> ints !! i == ints !! j where
l = length ints
它以其他方式工作:当条件不为真时,它只是丢弃当前的测试用例。但要小心:如果抛出的案例太多(条件限制太多),那么测试就变得不那么有用了。使用shrink
测试数据通常可以实现“无损”行为,但它是一个完整的其他主题。
答案 2 :(得分:0)
我遇到了与你类似的情况,我终于找到了如何在这里使用==>
:http://www.cse.chalmers.se/~rjmh/QuickCheck/manual.html,在&#34;条件属性&#34;部分。
根据您的示例,您必须将Bool
替换为Property
,并在属性测试之前插入有关变量的要求,如下所示:
prop_Myfunc :: [Int] -> (Int,Int) -> Property
prop_Myfunc ints (i,j) = (i >= 0 && j >= 0) ==> ints !! i == ints !! j
(我还没有对这个特殊的例子进行过测试,但在类似的情况下,它对我有用。)
请注意==>
的类型:(==>) :: Testable prop => Bool -> prop -> Property
。