tl;dr
我想了解如何使用Test.QuickCheck
来测试那些参数被传递给智能构造函数和/或被认为来自智能构造函数的函数。
长版本
在一个模块中,我有一个用户定义的类型,如下所示:
newtype SpecialStr = SpecialStr { getStr :: String }
顾名思义,SpecialStr
是非常特殊的,因为被包裹的String
不是";任何";字符串,但它必须满足某些属性。为了实现这一点,我不从模块中导出值构造函数,而是导出一个智能构造函数:
specialStr :: String -> SpecialStr
specialStr str = assert (isValid str) $ SpecialStr str
where
isValid :: String -> Bool
isValid = and . map (`elem` "abcdef") -- this is just an example logic
当然,我已经定义了一些使用这些SpecialStr
操作的函数,例如
someFunc :: String -> [SpecialStr]
someFunc str = -- uses smart constructor
someOtherFunc :: (Int, SpecialStr) -> Whatever
someOtherFunc = -- assumes the input has been created via the smart constructor, i.e. assumes it's valid
其中,可能someFunc
被馈送有String
,然后输出的[SpecialStr]
被压缩有[1..]
,结果被馈送到someOtherFunc
,只是为了做一个随机的例子。
现在我的问题是:如何使用QuickCheck
测试这些函数?
有智能构造函数吗?编写一个智能任意实例。
instance Arbitrary SpecialStr where
arbitrary = SpecialStr <$> listOf (choose ('a', 'f'))
shrink (SpecialStr s) = SpecialStr (shrinkList (enumFromTo 'a') s)
然后像往常一样写下你的财产。
-- check that someOtherFunc is hypermonotonic in the SpecialStrings
quickCheck (n1 n2 s1 s2 -> someOtherFunc (n1, min s1 s2) <= someOtherFunc (n2, max s1 s2))
或者其他什么。