我有一个带有以下类型签名的函数
rndListIndex :: Double -> Double -> Double -> Double
rndListIndex maxIdx r1 r2 = …
该函数具有
的属性prop_alwaysLessThanMaxIdx idx r1 r2 = (rndListIndex idx r1 r2 <= idx)
如何分别为maxIdx
和r1
,r2
生成随机数据;我知道函数choose
但不知道如何将它与多个输入变量一起使用。
目前我已使用固定idx
测试了该属性,这不是应该测试的方式。
答案 0 :(得分:13)
您必须使用QuickCheck中的forAll功能。它有以下类型:
forAll :: (Show a, Testable prop)
=> Gen a -- ^ The generator to use for generating values
-> (a -> prop) -- ^ A function which returns a testable property
-> Property
forAll
有两个参数:
Testable
实例的值,例如另一个Property
,Bool
或函数。 使用choose和elements生成器嵌套forAll的示例:
-- This generates a Property p for all x's in the closed interval [1,3]
-- The property p in turn generates a property q for all y ∈ [4,5]
-- The property q is True if x < y.
prop_choose = forAll (choose (1,3)) $ \x ->
forAll (elements [4,5]) $ \y -> x < y
对于您的测试属性,您可以使用forAll并选择第二个和第三个参数。
对于第一个参数,QuickCheck中有Positive a
类型,可用于生成类型a的任意正值(当a为Num时,它具有任意实例):
prop_alwayLessThanMaxIdx :: Positive Integer -> Property
prop_alwaysLessThanMaxIdx (Positive idx) =
forAll (choose (0,1)) $ \r1 ->
forAll (choose (0,1)) $ \r2 ->
(rndListIndex idx r1 r2) < idx
答案 1 :(得分:1)
我建议您定义自己的包装Double
的类型并为其指定一个Arbitrary
实例,该实例仅生成0到1之间的数字。例如:
import Test.QuickCheck
newtype UnitInterval = Unit Double deriving Show
instance Arbitrary UnitInterval where
arbitrary = fmap Unit (choose (0, 1))
shrink (Unit x) = [ Unit y | y <- shrink x, 0 <= y && y <= 1 ]
要生成idx
,您可以使用QuickCheck的Positive
修饰符,如@bennoffs建议的那样(您必须导入Test.QuickCheck.Modifiers
)。这类似于我在上面定义的UnitInterval
类型,但生成正数而不是0到1之间的数字。您的属性将如下所示:
prop_alwaysLessThanMaxIdx (Positive idx) (Unit r1) (Unit r2) =
rndListIndex idx r1 r2 <= idx