Creating Numbers With AutoFixture by Mark Seemann
Previously, we saw how AutoFixture creates strings. In this post, I'll explain how it creates numbers. Once again, the algorithm that I'll explain here is the default algorithm, but if you don't like it, you can replace it with something else.
It's very simple: Numbers are returned in the ordered sequence of natural numbers (1, 2, 3, 4, 5, …). The first time you call
fixture.CreateAnonymous<int>();
the returned number will be 1, the second time 2, etc.
The reason I chose that particular algorithm is because it creates numbers that we, as humans, find… well… natural!
A lot of the domains we model work with natural numbers, and even if you write an API where negative numbers are allowed, it's fairly unlikely that positive numbers will not be allowed. Thus, in most cases, small positive integers tend to be ‘nice' values in most APIs - and recall that when we do TDD, we focus on the Happy Path, so it's important to pick values that take us down that path.
Using the overload that takes a seed, like this:
fixture.CreateAnonymous(42);
has no effect - the seed (in this case 42) is simply ignored, so if you call this after first calling the parameterless overload twice, the return number is going to be 3.
Each number type, however, has its own sequence, so even if you've been creating a few Int32 instances like above,
fixture.CreateAnonymous<decimal>();
will return 1.
The following number types all work that way:
- Byte
- Decimal
- Double
- Int16
- Int32
- Int64
- SByte
- Single
- UInt16
- UInt32
- UInt64
Comments
For complex objects (say: a class with two writable properties of the same number type) the ordering of assignment is undefined even though the sequence of numbers is deterministic. In other words, if you have the properties Number1 and Number2, you know one gets the value 1 and the other gets the value 2, but you don't know which one gets what (it's probably deterministic anyway because Reflection is likely to always return properties in the same order, but AutoFixture does nothing to explicitly order properties and fields).
Another similar strategy could be to use random numbers from a constant seed. This would give you another stable sequence of numbers.
If none of the above is a concern (numbers do not influence the execution path) you can also choose to use pure random numbers.
In any case you can use the Register method to override the default behavior for a given type, so it's entirely possible to set it up with random numbers instead of a rising sequence.
fixture.Customize<int>(c => c.FromSeed(i => i));