简体   繁体   中英

Custom Testable instance with QuickCheck

I have a custom result/error monad, nothing fancy:

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

I want values in this monad to instantiate QuickCheck's Testable class, so I can write properties that hold (ie pass tests) when a value is Success _ , and not hold (ie fail tests) when a value is Error _ .

For example, I would like to be able to write a test like this:

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

and have the String in the Error be the test failure message if the test fails.

I assume I need to instantiate Testable for MyResult :

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

However I can't figure out how I should implement the property function in Testable , despite reading the QuickCheck documentation and relevant source code .

Any help here is greatly appreciated.

You need to make a Property from your result. The easiest way to do this is

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

You could also convert your Error result to a Quickcheck Result

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

See https://hackage.haskell.org/package/QuickCheck-2.9.2/docs/src/Test-QuickCheck-Property.html for the definition of failed

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM