Real World Haskell - Chapter 11. Testing and Quality Assurance

 

 

 

 

Testing Case Study: Specifying a Pretty Printer

 

(<>) 是连接两个Doc 的函数,加上fold 就变成连接多个Doc 的函数

 

Generating Test Data

 

data Doc = Empty

         | Char Char

         | Text String

         | Line

         | Concat Doc Doc

         | Union Doc Doc

         deriving (Show,Eq)

 

QuickCheck 提供了一个名为Arbitrary typeclass class 是定义typeclass 的关键字。定义一个typeclass 就是定义一组泛型函数。

 

QuickCheck 库中arbitrary 函数的定义

class Arbitrary a where

    arbitrary :: Gen a

 

这里的Gen 是一个Monad

 

QuickCheck 库中三个函数的定义

 

elements :: [a] -> Gen a

choose :: Random a => (a, a) -> Gen a

oneof :: [Gen a] -> Gen a

 

为简单的数据类型编写生成器

 

data Ternary

    = Yes

    | No

    | Unknown

    deriving (Eq,Show)

 

Ternary 是一个ternary logic

 

我们可以为Ternary 实现一个Arbitrary 的实例

 

-- 方法一

instance Arbitrary Ternary where

    arbitrary = elements [Yes, No, Unknown]

 

-- 方法二

instance Arbitrary Ternary where

    arbitrary = do

        n <- choose (0, 2) :: Gen Int

        return $ case n of

                    0 -> Yes

                    1 -> No

                    _ -> Unknown

 

instance (Arbitrary a, Arbitrary b) => Arbitrary (a, b) where

    arbitrary = do

        x <- arbitrary

        y <- arbitrary

        return (x, y)

 

instance Arbitrary Char where

    arbitrary = elements (['A'..'Z'] ++ ['a' .. 'z'] ++ " ~!@#$%^&*()")

 

生成任意类型的随机数据

 

-- 方法一

instance Arbitrary Doc where

    arbitrary = do

        n <- choose (1,6) :: Gen Int

        case n of

            1 -> return Empty

            2 -> do x <- arbitrary

                    return (Char x)

            3 -> do x <- arbitrary

                    return (Text x)

            4 -> return Line

            5 -> do x <- arbitrary

                    y <- arbitrary

                    return (Concat x y)

            6 -> do x <- arbitrary

                    y <- arbitrary

                    return (Union x y)

 

-- 方法二

instance Arbitrary Doc where

    arbitrary =

        oneof [ return Empty

              , liftM Char arbitrary

              , liftM Text arbitrary

              , return Line

              , liftM2 Concat arbitrary arbitrary

              , liftM2 Union arbitrary arbitrary ]

 

生成随机DOC

 

docs <- sample' (arbitrary::Gen [Doc]) 

print docs

-- >[[],[],[Char 's',Text "Om/b",Char 'w'],[Empty,Empty,Text "/149", .. =/"/188/150y"]]

 

Testing Document Construction

 

Doc 的两个基础函数

 

-- 生成空文档

empty :: Doc

empty = Empty

 

-- 合并两个文档

(<>)  :: Doc -> Doc -> Doc

Empty <> y = y

x <> Empty = x

x <> y = x `Concat` y

 

其它基础函数

 

char :: Char -> Doc

char c = Char c

 

text :: String -> Doc

text "" = Empty

text s  = Text s

 

double :: Double -> Doc

double d = text (show d)

 

line :: Doc

line = Line

 

验证一个文档与空文档合并什么也不会发生

 

prop_empty_id x =

      empty <> x == x

    &&

      x <> empty == x

 

-- quickCheck prop_empty_id  -- >+++ OK, passed 100 tests.

-- verboseCheck prop_empty_id

 

其它基础测试

 

prop_char c = char c == Char c

prop_text s = text s == if null s then Empty else Text s

prop_line = line == Line

prop_double d = double d == text (show d)

 

Using Lists as a Model

 

fold :: (Doc -> Doc -> Doc) -> [Doc] -> Doc

fold f = foldr f empty

 

hcat :: [Doc] -> Doc

hcat = fold (<>)  -- (<>) 是连接两个Doc 的函数,加上fold 就变成连接多个Doc 的函数

 

prop_hcat xs = hcat xs == glue xs

    where

        glue [] = empty

        glue (d:ds) = d <> glue ds

 

punctuate :: Doc -> [Doc] -> [Doc]

punctuate p [d]    = [d]

punctuate p (d:ds) = (d <> p) : punctuate p ds

punctuate p _      = []

 

prop_punctuate s xs = punctuate s xs == intersperse s xs

-- quickCheck prop_punctuate  -- 测试失败!*** Failed! Falsifiable (after 4 tests and 1 shrink):  Text "~"

 

-- 解决办法

 

prop_punctuate' s xs = punctuate s xs == combine (intersperse s xs)

    where

        combine [] = []

        combine [x] = [x]

        combine (x:Empty:ys) = x : combine ys

        combine (Empty:y:ys) = y : combine ys

        combine (x:y:ys) = x `Concat` y : combine ys

 

Putting It All Together

 

这一小节和下一节略。因为Test.QuickCheck.Batch  在新版本的QuickCheck 库不存了,待以后补充。

 

更多信息搜索stackoverflow

 

http://stackoverflow.com/search?page=1&tab=relevance&q=quickcheck

 

Measuring Test Coverage with HPC

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值