QuickCheckを試す

30分プログラム、その94。QuickCheckを試す。
同じく、仕様に基づいたテストを行なうらしいRSpecの参考になるかな、と思って。
いいよ、これ。テストデータが自動で作られるのは、新鮮。

使い方

例えば、lengthが満しているべき性質を関数で記述する。

pLengthApp:: [Int]->[Int]->Bool
pLengthApp xs ys = 
    myLength (xs++ys) == (myLength xs) + (myLength ys)

そして、これをquickCheckに渡す。

*Main > quickCheck pLengthApp
OK, passed 100 tests.

xsやysを自動で生成してくれるのがポイント。

あとは、論文に書いてあった特徴を列挙しておく。

  • テストデータの生成はカスタマイズできる
  • カスタマイズできるので、ユーザ定義型も生成できる
  • 関数も自動生成するよ
  • 生成するデータに条件もつけれる。ソートずみのリストとか
  • 生成するデータの分布をかえられるよ。

ソースコード

import Test.QuickCheck

--- length
-- myLength [] = 0
-- myLength (x:xs) = 1 + (myLength xs)
myLength xs = foldl (\x _-> x + 1) 0 xs

pLengthUnit:: [Int]->Bool
pLengthUnit x = myLength [x] == 1

pLengthApp:: [Int]->[Int]->Bool
pLengthApp xs ys = 
    myLength (xs++ys) == (myLength xs) + (myLength ys)

-- reverse
--myReverse [] = []
--myReverse (x:xs) = (reverse xs) ++ [x]
myReverse xs = foldl (flip (:)) [] xs

pReverseUnit :: Int -> Bool
pReverseUnit x = [x] == myReverse [x]
pReverseApp  :: [Int]->[Int]->Bool
pReverseApp xs ys = 
    myReverse (xs++ys) == (myReverse ys) ++ (myReverse xs)

-- append
append :: [a]->[a]->[a]
--append [] ys = ys
--append (x:xs) ys = x:(append xs ys)
append xs ys = foldr (:) ys xs

pAppendUnit :: [Int]-> Bool
pAppendUnit x = (append [] x) == x

pAppendApp :: [Int]->[Int]->Property
pAppendApp xs ys = 
    not (null xs) ==> 
        let hd = head xs
            tl = tail xs in
        (append xs ys) == hd:(append tl ys)

main = quickCheck pLengthUnit >>
       quickCheck pLengthApp >>
       quickCheck pReverseUnit >>
       quickCheck pReverseApp >>
       quickCheck pAppendUnit >>
       quickCheck pAppendApp