簡體   English   中英

如何在QuickCheck中編寫新的修飾符

[英]How do you write a new modifier in QuickCheck

我在使用QuickCheck進行測試時遇到了一些實例,這些實例在某些情況下可以簡化編寫我自己的修飾符的過程,但是我不確定如何做到這一點。 特別是,了解如何為列表和數字的生成器(例如Int )的生成器編寫修飾符將很有幫助。 我知道該庫中已經存在NonEmptyListPositiveNonNegative ,但是在某些情況下,如果我可以指定一個不僅是NonEmpty的列表,還可以是NonSingleton的列表,它會使我的測試更加清晰(因此,它至少包含2個元素),或者大於1的Int ,而不僅僅是NonZeroPositive ,或者是偶數/奇數的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組合器來編寫它。

該函數僅生成兩個值x1x2以及任意大小的列表xs (可以為空),並創建所有三個值的列表。 由於x1x2保證為單個值,因此結果列表將至少具有這兩個值。

過濾

有時,您只想丟棄生成值的一小部分。 您可以使用內置的==>組合器,直接在屬性中使用它:

moreThanOne :: (Ord a, Num a) => Positive a -> Property
moreThanOne (Positive i) = i > 1 ==> i > 1

雖然這個屬性是同義反復,它證明了你的地方,左側的謂詞==>確保上的右側,無論運行==>已通過謂語。

現有的單子組合器

由於Gen aMonad實例,因此您也可以使用現有的MonadApplicativeFunctor組合器。 這是將任何Functor任何數字轉換為偶數的一種:

evenInt :: (Functor f, Num a) => f a -> f a
evenInt = fmap (* 2)

請注意,這適用於任何 Functor f ,不僅適用於Gen a 但是,由於Gen aFunctor ,您仍然可以使用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文檔 我特別發現chooseelementsoneofsuchThat表達附加約束非常有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM