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

florin
Having them sequence ordered sounds like there will not be so "non-deterministic". Wouldn't a random number be more appropriate as it would allow testing of different cases each time. Sure it would not be reproducible but at least you will get to know that there might be something wrong with the code under test.
2010-05-21 10:29 UTC
The idea about constrained non-determinism is that although test values are essentially unknown, two consecutive test runs must traverse the same branch of source code each time. In some SUTs different integer values may cause different branches to be exectured for each test run, so I found it safer to use a deterministic sequence.

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.
2010-05-21 12:33 UTC
If you offer an overload for the constructor that takes a seed, when/how is it used? As you say, it does not work in this case.
2011-03-05 23:16 UTC
Let's say that you want to change the integer algorithm to return the seed. This can be done like this:

fixture.Customize<int>(c => c.FromSeed(i => i));
2011-03-06 04:24 UTC


Wish to comment?

You can add a comment to this post by sending me a pull request. Alternatively, you can discuss this post on Twitter or Google Plus, or somewhere else with a permalink. Ping me with the link, and I may add it as a comment.

Published

Friday, 03 April 2009 21:07:13 UTC

Tags



"Our team wholeheartedly endorses Mark. His expert service provides tremendous value."
Hire me!