QuickCheck测试自定义类型

时间:2014-11-23 21:50:28

标签: haskell functor quickcheck

使用以下代数数据类型:

data Cons a = Cons a (Cons a) | Empty deriving (Show, Eq)

我写了一个Arbitrary的实例:

我的理解是为QuickCheck创建Arbitrary的实例,以了解如何找到插入其Cons Int的测试。

instance Arbitrary (Cons Int) where
    arbitrary = elements [Empty, Cons 10 (Cons 100 (Cons 55 Empty)), Cons 1 Empty]

和一个功能:

makeArbitraryCons :: Gen (Cons Int)
makeArbitraryCons = arbitrary 

然后,我写了一个QuickCheck测试:

prop_id_functor_law_int ::  Cons Int -> Bool
prop_id_functor_law_int x = fmap id x == id x

它有效:

ghci> quickCheck prop_id_functor_law_int
*** Failed! Falsifiable (after 1 test):
Cons 10 (Cons 100 (Cons 55 Empty))

但是,当我尝试运行以下测试时,它会失败:

second_functor_law_int :: (Int -> Int) -> (Int -> Int) -> Cons Int -> Bool
second_functor_law_int f g x = left == right
  where left = fmap (f . g) $ x
        right = (fmap f) . (fmap g) $ x

出现此错误:

ghci> quickCheck second_functor_law_int

<interactive>:418:1:
    No instance for (Show (Int -> Int))
      arising from a use of `quickCheck'
    In the expression: quickCheck second_functor_law_int
    In an equation for `it': it = quickCheck second_functor_law_int

我的问题是:

  1. 是否需要为新的Arbritrary实例定义 数据类型(例如我的Cons a)?
  2. 我必须创建一个函数 创建Gen (Cons Int) - makeArbitraryCons
  3. 最后,当我通过quickCheck second_functor_law_int进行第二次测试时发生了什么?

1 个答案:

答案 0 :(得分:1)

1&amp; 2.您可以:定义Arbitrary实例或创建Gen ...函数并使用类似forAll组合器的内容。

有关使用forAll功能Gen ...的示例,请参阅this answer

  1. second_functor_law_int的签名是:

    second_functor_law ::(Int - &gt; Int) - &gt; (Int - &gt; Int) - &gt; Cons Int - &gt;布尔

  2. 所以通过运行quickCheck second_functor_law_int,您要求QuickCheck创建一个随机Int -> Int函数。 Quickcheck要求其随机生成的参数是可显示的,因此您会收到此错误,因为函数(通常)没有Show个实例。

    根据您拥有的内容,可以使用特定功能quickCheckf来呼叫g,例如:

    quickCheck $ second_functor_law_int_int (+1) (*2)
    

    然后,QuickCheck将只生成随机Cons Int值。

    顺便说一句,为arbitrary之类的ADT定义Cons的更好方法是使用sized。一些例子: