moodmosaic (Nikos Baxevanis)
Blog - About - Open Source - Bookmarks - Tags

# Observing the size of generated test data

Saturday, 21 March 2015

QuickCheck has a function called `sample` which, given a generator, prints some examples values to the standard output (stdout).

It’s signature is:

``````sample :: Show a => Gen a -> IO ()
``````

### Example

Using the `choose` generator we can use `sample` to generate random integers in the inclusive range [0, 9] and print them:

``````λ sample \$ choose (0, 9 :: Int)
``````

Output:

``````1
5
0
2
3
4
6
5
5
4
1
``````

## The sample function defined in FsCheck

FsCheck also defines a `sample` function, though it behaves in a slightly different way, as it takes two additional arguments `size` and `n`:

``````val sample : size:int -> n:int -> gn:Gen<'a> -> 'a list

// `size` is the size of generated test data
// `n` is the number of samples (defaults to 11 in QuickCheck)
``````

Let’s pause here and run `sample` by supplying different values for `size`.

### Using 0 for size

``````
open FsCheck.Gen

let sample'  = sample 0 11 // Size = 0, Number of samples = 11
let sample'' = sample' <| choose (0, 9)
``````

Output:

``````Length = 11
[0]: 4
[1]: 0
[2]: 4
[3]: 0
[4]: 3
[5]: 9
[6]: 3
[7]: 9
[8]: 2
[9]: 8
[10]: 2
``````

However, since size is `0` the result should be:

``````Length = 11
[0]: 0
[1]: 0
[2]: 0
[3]: 0
[4]: 0
[5]: 0
[6]: 0
[7]: 0
[8]: 0
[9]: 0
[10]: 0
``````

### Using 1000 for size

``````open FsCheck.Gen

let sample'  = sample 1000 11 // Size = 1000, Number of samples = 11
let sample'' = sample' <| choose (0, 9)
``````

Output:

``````Length = 11
[0]: 8
[1]: 6
[2]: 2
[3]: 3
[4]: 7
[5]: 3
[6]: 1
[7]: 2
[8]: 6
[9]: 2
[10]: 0
``````

The above result looks incorrect, in fact it looks the same as the first result, where size was 0.

Since size is `1000` the result should look like:

``````Length = 11
[0]: -78
[1]: 347
[2]: 242
[3]: 707
[4]: 414
[5]: 49
[6]: 551
[7]: 45
[8]: 897
[9]: -99
[10]: 77
``````

At this point, we observed that if a generator ignores size (e.g. as `choose` does) then `sample` ignores it’s `size` parameter.

## Just sample with a different generator, then.

Instead of the `choose` generator, the following example uses `generate<int>`.

### Using 0 for size

``````open FsCheck.Arb
open FsCheck.Gen

let sample'  = sample 0 11 // Size = 0, Number of samples = 11
let sample'' = sample' <| generate<int>
``````

The results are now looking good:

``````Length = 11
[0]: 0
[1]: 0
[2]: 0
[3]: 0
[4]: 0
[5]: 0
[6]: 0
[7]: 0
[8]: 0
[9]: 0
[10]: 0
``````

That’s because `generate<int>` takes `size` into account.

### Using 1000 for size

``````open FsCheck.Arb
open FsCheck.Gen

let sample'  = sample 1000 11 // Size = 1000, Number of samples = 11
let sample'' = sample' <| generate<int>
``````

The results are now looking good:

``````Length = 11
[0]: -98
[1]: 307
[2]: 142
[3]: 507
[4]: 414
[5]: 39
[6]: 501
[7]: 4
[8]: 807
[9]: -81
[10]: 31
``````

## How to always control the size of test data, then?

That seems to be the purpose of the `sized` function.

For the sake of completeness, here’s the original example with `choose` rewritten to use `sized`:

### sample and choose, using 0 for size

``````open FsCheck.Gen

let sample'  = sample 0 11 // Size = 0, Number of samples = 11
let sample'' = sample' <| (sized <| fun s -> choose (0, s))
``````

Results to the following, which is now correct:

``````Length = 11
[0]: 0
[1]: 0
[2]: 0
[3]: 0
[4]: 0
[5]: 0
[6]: 0
[7]: 0
[8]: 0
[9]: 0
[10]: 0
``````

### sample and choose, using 1000 for size

``````open FsCheck.Gen

let sample'  = sample 1000 11 // Size = 1000, Number of samples = 11
let sample'' = sample' <| (sized <| fun s -> choose (-s, s))
``````

Results to the following, which now looks correct:

``````Length = 11
[0]: 105
[1]: 682
[2]: -239
[3]: 658
[4]: -6
[5]: 9
[6]: 203
[7]: -43
[8]: 304
[9]: -125
[10]: -423
``````

• QuickCheck
• FsCheck

## Appendix

The above F# examples use the backward pipe `<|` operator to look similar to the Haskell examples. In F#, it’s idiomatic to use the forward pipe operator instead.</p>

Using the forward pipe operator, the previous example would be:

``````let result =
(fun s -> Gen.choose (-s, s))
|> Gen.sized
|> Gen.sample 1000 11
``````
━━━

This post has been filed under #fscheck #haskell #quickcheck #f#

### Feedback

Have feedback on this page? Let @nikosbaxevanis know on twitter. Need help or found a bug? Contact me.

© 2011-2018 Nikos Baxevanis. All written content on this site is provided under a Creative Commons ShareAlike license. All code is provided under a MIT license unless otherwise stated.