Customizing A Type's Builder With AutoFixture by Mark Seemann
In the previous post on AutoFixture, I demonstrated how it's possible to use a customized Builder to perform complex initialization when requesting an instance of a particular type. To recap, this was the solution I described:
var mc = fixture.CreateAnonymous<MyClass>(); var mvm = fixture.Build<MyViewModel>() .Do(x => x.AvailableItems.Add(mc)) .With(x => x.SelectedItem, mc) .CreateAnonymous();
This code first creates an anonymous instance of MyClass that can be added to MyViewModel. It then initializes a Builder for a specific instance of MyViewModel, instructing it to
- add the anonymous MyClass instance to the list of AvailableItems
- assign the same instance to the SelectedItem property
While this works splendidly, it can get tiresome to write the same customization over and over again if you need to create multiple instances of the same type. It also violate the DRY principle.
When this is the case, you can alternatively register a customized Builder pipeline for the type in question (in this case MyViewModel). This is done with the Customize method:
var mc = fixture.CreateAnonymous<MyClass>(); fixture.Customize<MyViewModel>(ob => ob .Do(x => x.AvailableItems.Add(mc)) .With(x => x.SelectedItem, mc));
The Customize method takes as input a function that provides an initial ObjectBuilder as input, and returns a new, customized ObjectBuilder as output. This function is registered with the type, so that each time an anonymous instance of the type is requested, the customized ObjectBuilder will be used to create the instance.
In the example, I customize the supplied ObjectBuilder (ob) in exactly the same way as before, but instead of invoking CreateAnonymous, I simply return the customized ObjectBuilder to the Fixture instance. It then saves this customized ObjectBuilder for later use.
With this customization, what before failed now succeeds:
var mvm = fixture.CreateAnonymous<MyViewModel>();
The Customize method is the core method for customizing AutoFixture. Most other customization methods (like Register) are simply convenience methods that wraps Customize. It is a very powerful method that can be used to define some very specific Builder algorithms for particular types.