I thought it's time to try out FsCheck but it proves tougher than I thought. There's a lot of documentation on Arb
, generators and so on, but there doesn't seem to be any guidance in how to apply that knowledge. Or I'm just not getting it.
What may make it harder to grasp is that the relation between tests, properties, generators, arbitraries, shrinking and, in my case, randomness (some tests automatically generate random data, others don't) is not clear to me. I don't have a Haskell background so that doesn't help much either.
Now for the question: how do I generate random integers?
My test scenario can be explained on the properties of multiplication, let's say distributivity:
static member ``Multiplication is distributive`` (x: int64) y z =
let res1 = x * (y + z)
let res2 = x * y + x * z
res1 = res2
// run it:
[<Test>]
static member FsCheckAsUnitTest() =
Check.One({ Config.VerboseThrowOnFailure with MaxTest = 1000 }, ``Multiplication is distributive``)
When I run this with Check.Verbose
or the NUnit integration, I get test sequences like:
0:
(-1L, -1L, -1L)
1:
(-1L, -1L, 0L)
2:
(-1L, -1L, -1L)
3:
(-1L, -1L, -1L)
4:
(-1L, 0L, -1L)
5:
(1L, 0L, 2L)
6:
(-2L, 0L, -1L)
7:
(-2L, -1L, -1L)
8:
(1L, 1L, -2L)
9:
(-2L, 2L, -2L)
After 1000 tests it hasn't gotten over 100L
. Somehow I imagined this would "automatically" choose random numbers evenly distributed over the whole range of int64
, at least that's how I interpreted the documentation.
Since it doesn't, I started experimenting and came up with silly solutions like the following to get higher numbers:
type Generators =
static member arbMyRecord =
Arb.generate<int64>
|> Gen.where ((<) 1000L)
|> Gen.three
|> Arb.fromGen
But this becomes incredibly slow and is clearly not the right approach. I'm sure there must be a simple solution that I'm missing. I tried with Gen.choose(Int64.MinValue, Int64.MaxValue)
, but this only supports ints, not longs (but even with just ints I couldn't get it working).
In the end I need a solution that works for all the primitive numeric data types, that includes their maxes and mins, their zeroes and ones, and some random selection from whatever is within.
MaxTest = 1000
, see code above. But that doesn't help. Perhaps you mean theStartTest
andEndTest
values, but setting these toInt32.MinValue/MaxValue
has the effect that all permutations useInt32.MinValue
as a constant value. – Abel