使用 QuickCheck 的自定义可测试实例

Custom Testable instance with QuickCheck

我有一个自定义的 result/error monad,没什么特别的:

import Control.Monad (liftM, ap)

data MyResult a = Error String | Success a

instance Functor MyResult where
    fmap = liftM

instance Applicative MyResult where
    pure  = return
    (<*>) = ap

instance Monad MyResult where
    (Error   s) >>= f = Error s
    (Success a) >>= f = f a
    return = Success

我希望此 monad 中的值实例化 QuickCheck 的 Testable class,因此我可以编写在值为 Success _ 时保持(即通过测试)的属性,而不保持(即测试失败)当值为 Error _.

例如,我希望能够编写这样的测试:

myProp :: Property
myProp = forAll (arbitrary :: Int)
    (\x -> if x == 0 then Error "0 not allowed" else Success ())

如果测试失败,Error 中的 String 将作为测试失败消息。

我假设我需要为 MyResult:

实例化 Testable
instance Testable t => Testable (MyResult t) where
    property (Success _) = undefined -- what goes here?
    property (Error   s) = undefined -- what goes here?

然而,尽管阅读了 QuickCheck documentation and relevant source code.

,但我无法弄清楚如何在 Testable 中实现 property 函数

非常感谢任何帮助。

您需要根据结果生成 Property。最简单的方法是

property (Success _) = property True
property (Error _)   = property False

您还可以将 Error 结果转换为快速检查 Result

property (Error s)   = property $ failed { reason = s }

有关 failed

的定义,请参阅 https://hackage.haskell.org/package/QuickCheck-2.9.2/docs/src/Test-QuickCheck-Property.html