Using Haskell’s QuickCheck to generate random test data
QuickCheck is a random testing library written in Haskell and is typically used for fuzz testing code. The main typeclass provided by QuickCheck is the Arbitrary typeclass. When you make one of your data types an instance of this typeclass (by implementing the arbitrary function) you can generate random samples of those data types
I recently needed a way to generate a large number of Serial numbers of a specific format, QuickCheck turned out to be perfect for this.
I started out by creating a new data type representing my serial number:
data Serial = Serial String Int
The String represents a random prefix (eg. “ABC”), and the Int represents some number which could represent the order number, etc. Implementing show allows me to easily convert this data type to a string:
instance Show Serial where
show (Serial prefix number) = prefix ++ show number
Now to generate Serials we implement Arbitrary for our Serial type:
instance Arbitrary Serial where
arbitrary = do
prefix <- vectorOf 3 $ elements ['A'..'Z']
number <- choose (10000, 99999)
return $ Serial prefix number
The magic happens during the call to arbitrary. arbitrary returns the type Gen Serial which represents a computation that generates a random Serial. Gen is a Monad, so that allows us to use do notation to build our generating computation.
The first line in our do block is a call to elements, which chooses a single element out of a list of elements. The vectorOf 3 says to apply this generator 3 times and assign it to prefix. As you can probably guess by now this generates a random string of length 3 with random characters between ‘A’ and ‘Z’.
The second line in the do block is a call to choose which chooses a single value between a range of values.
Finally we return our serial with the generated prefix and number.
We can now generate a list of random serials by using unGen:
serialGen :: Int -> [Serial]
serialGen seed = unGen arbitrary (mkStdGen seed) 9999999
Some data from this function:
LWQ74236
IZK97057
MTT84566
FBL91704
OUX61740
GFX20409
SGO76263
SXE22215
JNH61151
ZQY93980
Naturally you can apply this method to any data type you can think of, the Gen Monad is a great DSL for generating random test data!
The full program: