Creating specific populated lists with AutoFixture by Mark Seemann
How do you get AutoFixture to create populated lists or sequences of items? Recently I seem to have been getting this question a lot, and luckily it's quite easy to answer.
Let's first look at the standard AutoFixture behavior and API.
You can ask AutoFixture to create an anonymous List like this:
var list = fixture.CreateAnonymous<List<int>>();
Seen from AutoFixture's point of view, List<int> is just a class like any other. It has a default constructor, so AutoFixture just uses that and returns an instance. You get back an instance, no exceptions are thrown, but the list is empty. What if you'd rather want a populated list?
There are many ways to go about this. A simple, low-level solution is to populate the list after creation:
However, you may instead prefer getting a populated list right away. This is also possible, but before we look at how to get there, I'd like to point out a feature that surprisingly few users notice. You can create many anonymous specimens at once:
var integers = fixture.CreateMany<int>();
Armed with this knowledge, as well as the knowledge of how to map types, we can now create this customization to map IEnumerable<int> to CreateMany<int>:
fixture.Register(() => fixture.CreateMany<int>());
The Register method is really a generic method, but since we have type inference, we don't have to write it out. However, since CreateMany<int>() returns IEnumerable<int>, this is the type we register. Thus, every time we subsequently resolve IEnumerable<int>, we will get back a populated sequence.
Getting back to the original List<int> example, we can now customize it to a populated list like this:
fixture.Register(() => fixture.CreateMany<int>().ToList());
Because the ToList() extension method returns List<T>, this call registers List<int> so that we will get back a populated list of integers every time the fixture resolves List<int>.
What about other collection types that don't have a nice LINQ extension method? Personally, I never use Collection<T>, but if you wanted, you could customize it like this:
fixture.Register(() => new Collection<int>( fixture.CreateMany<int>().ToList()));
Since Collection<T> has a constructor overload that take IList<T> we can customize the type to use this specific overload and populate it with ‘many' items.
Finally, we can combine all this to map from collection interfaces to populated lists. As an example, we can map from IList<int> to a populated List<int> like this:
fixture.Register<IList<int>>(() => fixture.CreateMany<int>().ToList());
When we use the Register method to map types we can no longer rely on type inference. Instead, we must explicitly register IList<int> against a delegate that creates a populated List<int>. Because List<int> implements IList<int> this compiles. Whenever this fixture instance resolves IList<int> it will create a populated List<int>.
All of this describes what you can do with the strongly typed API available in AutoFixture 2.0. It's easy and very flexible, but the only important drawback is that it's not general. All of the customizations in this post specifically address lists and sequences of integers, but not lists of any other type. What if you would like to expand this sort of behavior to any List<T>, IEnumerable<T> etc?
Stay tuned, because in the next post I will describe how to do that.