[英]How do you create quickCheck properties with a Property output in Haskell?
[英]How do you write a new modifier in QuickCheck
我在使用QuickCheck進行測試時遇到了一些實例,這些實例在某些情況下可以簡化編寫我自己的修飾符的過程,但是我不確定如何做到這一點。 特別是,了解如何為列表和數字的生成器(例如Int
)的生成器編寫修飾符將很有幫助。 我知道該庫中已經存在NonEmptyList
, Positive
和NonNegative
,但是在某些情況下,如果我可以指定一個不僅是NonEmpty的列表,還可以是NonSingleton的列表,它會使我的測試更加清晰(因此,它至少包含2個元素),或者大於1的Int
,而不僅僅是NonZero
或Positive
,或者是偶數/奇數的Int(egral)
等。
有很多方法可以做到這一點。 這是一些例子。
您可以將組合器編寫為函數。 這是一個從任何Gen a
生成非單個列表的列表:
nonSingleton :: Gen a -> Gen [a]
nonSingleton g = do
x1 <- g
x2 <- g
xs <- listOf g
return $ x1 : x2 : xs
它具有與內置listOf
函數相同的類型,並且可以以相同的方式使用:
useNonSingleton :: Gen Bool
useNonSingleton = do
xs :: [String] <- nonSingleton arbitrary
return $ length xs > 1
在這里,我利用Gen a
作為Monad
優勢,以便可以使用do
表示法來編寫函數和屬性,但是如果願意,也可以使用monadic組合器來編寫它。
該函數僅生成兩個值x1
和x2
以及任意大小的列表xs
(可以為空),並創建所有三個值的列表。 由於x1
和x2
保證為單個值,因此結果列表將至少具有這兩個值。
有時,您只想丟棄生成值的一小部分。 您可以使用內置的==>
組合器,直接在屬性中使用它:
moreThanOne :: (Ord a, Num a) => Positive a -> Property
moreThanOne (Positive i) = i > 1 ==> i > 1
雖然這個屬性是同義反復,它證明了你的地方,左側的謂詞==>
確保上的右側,無論運行==>
已通過謂語。
由於Gen a
是Monad
實例,因此您也可以使用現有的Monad
, Applicative
和Functor
組合器。 這是將任何Functor
任何數字轉換為偶數的一種:
evenInt :: (Functor f, Num a) => f a -> f a
evenInt = fmap (* 2)
請注意,這適用於任何 Functor f
,不僅適用於Gen a
。 但是,由於Gen a
是Functor
,您仍然可以使用evenInt
:
allIsEven :: Gen Bool
allIsEven = do
i :: Integer <- evenInt arbitrary
return $ even i
此處的arbitrary
函數調用都會創建一個不受限制的Integer
值。 然后, evenInt
乘以2就可以使它均勻。
您還可以使用newtype
創建自己的數據容器,然后使它們成為Arbitrary
實例:
newtype Odd a = Odd a deriving (Eq, Ord, Show, Read)
instance (Arbitrary a, Num a) => Arbitrary (Odd a) where
arbitrary = do
i <- arbitrary
return $ Odd $ i * 2 + 1
如果需要,這還使您能夠實現shrink
。
您可以在如下屬性中使用newtype
:
allIsOdd :: Integral a => Odd a -> Bool
allIsOdd (Odd i) = odd i
Arbitrary
實例對類型a
使用arbitrary
值以生成不受約束的值i
,然后將其加倍並加一個,從而確保該值是奇數。
查看更多內置組合器的QuickCheck文檔 。 我特別發現choose
, elements
, oneof
和suchThat
表達附加約束非常有用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.