Checkers是一个可重用的QuickCheck属性库,特别适用于 标准类型
如何编写检查器实例以测试我的应用验证实例是否有效?
import Test.QuickCheck
import Test.QuickCheck.Checkers
import Test.QuickCheck.Classes
import Control.Applicative
import Data.Monoid
data Validation e a =
Error e
| Scss a
deriving (Eq, Show)
instance Functor (Validation e) where
fmap _ (Error e) = Error e
fmap f (Scss a) = Scss $ f a
instance Monoid e => Applicative (Validation e) where
pure = Scss
(<*>) (Scss f) (Scss a) = Scss $ f a
(<*>) (Error g) (Scss a) = Error g
(<*>) (Scss a) (Error g) = Error g
(<*>) (Error a) (Error g) = Error $ mappend a g
instance (Arbitrary a, Arbitrary b) => Arbitrary (Validation a b) where
arbitrary = do
a <- arbitrary
b <- arbitrary
elements [Scss a, Error b]
instance (Eq a, Eq b) => EqProp (Validation a b) where (=-=) = eq
main :: IO ()
main = quickBatch $ applicative [(Scss "b", Scss "a", Scss "c")]
我想我差不多了,但是我得到了一个错误:
chap17/Validation_applicative.hs:36:21: No instance for (CoArbitrary (Validation e0 [Char])) …
arising from a use of ‘applicative’
In the second argument of ‘($)’, namely
‘applicative [(Scss "b", Scss "a", Scss "c")]’
In the expression:
quickBatch $ applicative [(Scss "b", Scss "a", Scss "c")]
In an equation for ‘main’:
main = quickBatch $ applicative [(Scss "b", Scss "a", Scss "c")]
Compilation failed.
我已尝试为验证添加CoArbitrary实例,如下所示:
instance CoArbitrary (Validation a b)
但这会导致出现此错误消息:
chap17/Validation_applicative.hs:35:10: No instance for (GHC.Generics.Generic (Validation a b)) …
arising from a use of ‘Test.QuickCheck.Arbitrary.$gdmcoarbitrary’
In the expression: Test.QuickCheck.Arbitrary.$gdmcoarbitrary
In an equation for ‘coarbitrary’:
coarbitrary = Test.QuickCheck.Arbitrary.$gdmcoarbitrary
In the instance declaration for ‘CoArbitrary (Validation a b)’
chap17/Validation_applicative.hs:38:21: No instance for (Eq e0) arising from a use of ‘applicative’ …
The type variable ‘e0’ is ambiguous
Note: there are several potential instances:
instance Eq a => Eq (Const a b) -- Defined in ‘Control.Applicative’
instance Eq a => Eq (ZipList a) -- Defined in ‘Control.Applicative’
instance Eq a => Eq (Data.Complex.Complex a)
-- Defined in ‘Data.Complex’
...plus 65 others
In the second argument of ‘($)’, namely
‘applicative [(Scss "b", Scss "a", Scss "c")]’
In the expression:
quickBatch $ applicative [(Scss "b", Scss "a", Scss "c")]
In an equation for ‘main’:
main = quickBatch $ applicative [(Scss "b", Scss "a", Scss "c")]
Compilation failed.
答案 0 :(得分:8)
要自动派生CoArbitrary
的实例,您的数据类型应该具有Generic
的实例,该实例也可以通过一些不错的语言扩展自动派生:
{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics
data Validation e a =
Error e
| Scss a
deriving (Eq, Show, Generic)
但是,您的计划中最重要的错误是您正在[]
对applicative [(Scss "b", Scss "a", Scss "c")]
进行测试,而不是applicative
对您自己的类型进行测试。这里是applicative :: forall m a b c.
( Applicative m
, Arbitrary a, CoArbitrary a, Arbitrary b, Arbitrary (m a)
, Arbitrary (m (b -> c)), Show (m (b -> c))
, Arbitrary (m (a -> b)), Show (m (a -> b))
, Show a, Show (m a)
, EqProp (m a), EqProp (m b), EqProp (m c)
) =>
m (a,b,c) -> TestBatch
applicative = const ( "applicative"
, [ ("identity" , property identityP)
, ("composition" , property compositionP)
, ("homomorphism", property homomorphismP)
, ("interchange" , property interchangeP)
, ("functor" , property functorP)
]
)
测试包的定义,省略了详细信息:
m
简而言之,给定了a
,b
,c
和m
这四种类型,此函数将创建一组a
- 作为属性的属性应用仿函数 - 应该满足,之后您可以使用b
生成的随机c
QuickCheck
[(Scss "b", Scss "a", Scss "c")]
值来测试它们。 [(Validation String, Validation String, Validation String)]
类型m ~ []
生成Validation e (a, b, c)
。
因此,您应该提供const
类型的某些值,或者根本没有值:您可能已经注意到applicative
的定义中的main :: IO ()
main = quickBatch $ applicative (undefined :: Validation String (Int, Double, Char))
,只有checkers
的类型争论很重要:
Validation String (Int, Double, Char)
之后,您可以运行测试并获得格式良好的结果。但不,你不应该以这种方式测试一个应用程序。
Maybe
提供的测试远远不够。通过GHC的运行时单形性以及它如何处理歧义,你必须提供四个具体的非多态类型来运行像Integer
这样的测试,测试模块将只生成和测试这四种类型,而您的applicative functor应该使用符合上下文的任何类型。
IMO大多数多态函数都不适合单元测试框架:它不能针对所有可能的类型进行测试,因此必须选择仅使用手选类型进行一些测试,或者进行测试键入足够通用(如你的代码需要任意monad时的Free monad,但通常&#34;足够通用&#34;在其他上下文中没有明确定义)。
您可以更严格地检查您的实施情况,并证明所有法律都满足所有法律要求,无论是使用笔和纸,还是使用像agda这样的证明引擎。以下是myGamePiece = new component(30, 30, "Pacman.png", 10, 210, "image");
上可能有所帮助的示例:Proving Composition Law for Maybe Applicative
<img id="green" src="PacmanGreen.png" draggable="true"
ondragstart="drag(event)" width="30" height="30">
是足够的&#34;&#34;用于单元测试多态函数的类型。我发现This blog article by Bartosz Milewski及其参考书目是抓住参数化和自由定理的好资源。