2012-10-10 13 views
16

假设我想为(!!)函数编写一些单元测试。如何判断QuickCheck只为参数生成有效的列表索引?

my_prop xs n = ... 

我想限制N到唯一有效的指标,我知道我可以做类似

my_prop xs n = (not.null) (drop n xs) ==> ... 

但是,这使得它如此,绝大多数的产生的情况是无效而被扔掉。有没有一种方法可以让QuickCheck生成xs列表,并使用它的值仅生成n的有效情况?

+1

创建一个新类型,其中包含一个列表和一个带有适当的'Arbitrary'实例的'Int'。 –

回答

17

使用forAll,您可以为n指定generator,该值取决于较早的参数,例如,

my_prop (NonEmpty xs) = forAll (choose (0, length xs - 1)) $ \n -> ... 
+0

整洁。如果我需要两个指数,我怎么能通过Gen(Int,Int)forAll?我目前的解决方案是嵌套forAll像这样:'forAll(indices xs)$ \ x - > forAll(indices xs)$ \ y - > ...'(使用Daniel Fischer的指数定义在另一个答案中看到)。 – Arild

10

可以使一台发电机,只有建立有效的索引,写你的财产像

import Test.QuickCheck 
import Test.QuickCheck.Gen 
import System.Random 

indices :: [a] -> Gen Int 
indices xs = MkGen $ \sg _ -> fst $ randomR (0, length xs - 1) sg 

my_prop :: [Char] -> Property 
my_prop xs = not (null xs) ==> forAll (indices xs) (\i -> xs !! i /= '0') 

消除Int说法。

5

正如Daniel Wagner所建议的,有一种可能性是创建我自己的数据类型并给它一个Arbitrary实例。

data ListAndIndex a = ListAndIndex [a] Int deriving (Show) 

instance Arbitrary a => Arbitrary (ListAndIndex a) where 
    arbitrary = do 
    (NonEmpty xs) <- arbitrary 
    n <- elements [0..(length xs - 1)] 
    return $ ListAndIndex xs n 

NonEmpty是从自定义类型中Test.QuickCheck.Modifiers用于产生非空列表。