我可以生成任意字符串,并避免在 QuickCheck 中重复规范吗?
Can I generate arbitrary strings, and avoid repeating specifications in QuickCheck?
给定
data MyType = MyType ...
makeMyType :: String -> String -> String -> MyType
-- ...
type StringThing = String
makeMyType
期望的字符串(分别)是:
- 一些自定义字符串的
-
定界字符串(例如,"Hilary-Jeb-David-Charles"
),
- 一个由 4 个大写字母组成的字符串,并且
- a
.
由 1 到 26 之间的整数分隔的字符串,每个整数用零到两个字符填充(例如,"04.23.11.09"
)
我可以使用 QuickCheck 来生成足够的测试用例,例如
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
import Test.QuickCheck
import Data.List (intercalate)
import Text.Printf (printf)
-- This really should be an arbitrary string of random length in some range
instance Arbitrary StringThing where
arbitrary = elements ["FUSHFJSHF","KLSJDHFLSKJDHFLSKJDFHLSKJDHFLSKJOIWURURW","GHSHDHUUUHHHA"]
instance Arbitrary MyType where
arbitrary = do
-- This repetition feels unnecessary
w1 <- elements ['A'..'Z']
w2 <- elements ['A'..'Z']
w3 <- elements ['A'..'Z']
w4 <- elements ['A'..'Z']
c1 <- elements someListOfCustomStuff
c2 <- elements someListOfCustomStuff
c3 <- elements someListOfCustomStuff
c4 <- elements someListOfCustomStuff
r1 <- choose (1,26)
r2 <- choose (1,26)
r3 <- choose (1,26)
r4 <- choose (1,26)
return $ makeMyType (intercalate "-" [c4,c3,c2,c1])
[w1,w2,w3,w4]
(intercalate "." $ (printf "%02d") <$> ([r1,r2,r3,r4] :: [Int]))
prop_SomeProp :: MyType -> StringThing -> Bool
prop_SomeProp mt st = ...
但是StringThing
确实应该在一定范围内接受随机长度的任意大写字母字符串,并且对所有w...
s、c..
s重复相同的规范, r....
s 似乎是不必要的。
QuickCheck 中有没有办法:
- 生成长度在一定范围内的随机字符串,仅限于某些字符,并且
- "share" 在多个值中使用
elements
或 choose
的规范?
是的。 Haskell 擅长将事情分解开来!您当然可以命名和共享子表达式,例如 elements ['A'..'Z']
capitals = elements ['A'..'Z']
instance Arbitrary StringThing where
arbitrary = do
l <- choose (1,50) -- this is your string length
replicateM l capitals
对于您的 MyType,您还可以大量使用 replicateM:
instance Arbitrary MyType where
arbitrary = do
ws <- replicateM 4 capitals
cs <- replicateM 4 (elements someListOfCustomStuff)
rs <- replicateM 4 (choose (1,26))
return $ makeMyType (intercalate "-" cs)
ws
(intercalate "." $ (printf "%02d") <$> (rs :: [Int]))
给定
data MyType = MyType ...
makeMyType :: String -> String -> String -> MyType
-- ...
type StringThing = String
makeMyType
期望的字符串(分别)是:
- 一些自定义字符串的
-
定界字符串(例如,"Hilary-Jeb-David-Charles"
), - 一个由 4 个大写字母组成的字符串,并且
- a
.
由 1 到 26 之间的整数分隔的字符串,每个整数用零到两个字符填充(例如,"04.23.11.09"
)
我可以使用 QuickCheck 来生成足够的测试用例,例如
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
import Test.QuickCheck
import Data.List (intercalate)
import Text.Printf (printf)
-- This really should be an arbitrary string of random length in some range
instance Arbitrary StringThing where
arbitrary = elements ["FUSHFJSHF","KLSJDHFLSKJDHFLSKJDFHLSKJDHFLSKJOIWURURW","GHSHDHUUUHHHA"]
instance Arbitrary MyType where
arbitrary = do
-- This repetition feels unnecessary
w1 <- elements ['A'..'Z']
w2 <- elements ['A'..'Z']
w3 <- elements ['A'..'Z']
w4 <- elements ['A'..'Z']
c1 <- elements someListOfCustomStuff
c2 <- elements someListOfCustomStuff
c3 <- elements someListOfCustomStuff
c4 <- elements someListOfCustomStuff
r1 <- choose (1,26)
r2 <- choose (1,26)
r3 <- choose (1,26)
r4 <- choose (1,26)
return $ makeMyType (intercalate "-" [c4,c3,c2,c1])
[w1,w2,w3,w4]
(intercalate "." $ (printf "%02d") <$> ([r1,r2,r3,r4] :: [Int]))
prop_SomeProp :: MyType -> StringThing -> Bool
prop_SomeProp mt st = ...
但是StringThing
确实应该在一定范围内接受随机长度的任意大写字母字符串,并且对所有w...
s、c..
s重复相同的规范, r....
s 似乎是不必要的。
QuickCheck 中有没有办法:
- 生成长度在一定范围内的随机字符串,仅限于某些字符,并且
- "share" 在多个值中使用
elements
或choose
的规范?
是的。 Haskell 擅长将事情分解开来!您当然可以命名和共享子表达式,例如 elements ['A'..'Z']
capitals = elements ['A'..'Z']
instance Arbitrary StringThing where
arbitrary = do
l <- choose (1,50) -- this is your string length
replicateM l capitals
对于您的 MyType,您还可以大量使用 replicateM:
instance Arbitrary MyType where
arbitrary = do
ws <- replicateM 4 capitals
cs <- replicateM 4 (elements someListOfCustomStuff)
rs <- replicateM 4 (choose (1,26))
return $ makeMyType (intercalate "-" cs)
ws
(intercalate "." $ (printf "%02d") <$> (rs :: [Int]))