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.
Comments
I posted this to CodePlex without properly thinking it through, but am now posting here which should be closer to where it belongs.
I have the following class that I am trying to test:
Specifically, I want to see if I have a license that was purchased more than X time periods ago, the expiration date calculates properly. For example, I have a test that is set up to use a 6 month license, with a purchase date from seven months ago. I am trying to force a certain date, so I got into customizing, and set up my test as follows:
I realize that this isn't a complete test, but I ran it just to see what feedback I'd get, to make certain I was customizing properly. Looks like I'm not, because I get an error:
Where have I gone wrong?
Thanks for your help.
Scott, thank you for writing. In your expression
b.DatePurchased == DateTime.Now.AddMonths(-7)
, what would you say the==
does?Mark, I really must apologize; my post above was not meant to be published. I worked on this a long time ago and I must have committed it to my local repository. I am very aware of the difference between
=
and==
. This must have been a question I had when I first started looking at AutoFixture (and working with Git). Again, my apologies.Scott