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

  1. add the anonymous MyClass instance to the list of AvailableItems
  2. 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

Scott Peterson

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:

public class License
    {
        public virtual DateTime DatePurchased { get; set; }
        public virtual int LicenseDuration { get; set; }
        public virtual EnumDatePeriod PeriodType { get; set; }
        public virtual bool InUse { get; set; }

        public DateTime ExpirationDate()
        {
            ILicenseCalculator calculator = CreateLicenseDurationBuilder(PeriodType);

            return calculator.CalculateLicenseDuration(DatePurchased, LicenseDuration);
        }

        public ILicenseCalculator CreateLicenseDurationBuilder(EnumDatePeriod datePeriod)
        {
            Dictionary<EnumDatePeriod, ILicenseCalculator> calculators = new Dictionary<EnumDatePeriod, ILicenseCalculator>();
            calculators.Add(EnumDatePeriod.Year, new YearLicenseCalculator());
            calculators.Add(EnumDatePeriod.Month, new MonthLicenseCalculator());
            calculators.Add(EnumDatePeriod.Week, new WeekLicenseCalculator());
            calculators.Add(EnumDatePeriod.Day, new DayLicenseCalculator());

            return calculators[datePeriod];
        }
    }

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:

[Fact]
        public void CanCalculateExpirationDateOnExpiredMonthlyLicense()
        {
            Fixture fixture = new Fixture();
            fixture.Customize<License>(x => x
                .With(b => b.DatePurchased == DateTime.Now.AddMonths(-7)));
            var sut = fixture.Create<License>();
        }

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:

Result Message:    
System.ArgumentException : The expression's Body is not a MemberExpression. Most likely this is because it does not represent access to a property or field. 
Parameter name: propertyPicker 

Where have I gone wrong?

Thanks for your help.

2015-02-26 21:39 UTC

Scott, thank you for writing. In your expression b.DatePurchased == DateTime.Now.AddMonths(-7), what would you say the == does?

2015-02-27 7:35 UTC
Scott Peterson

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

2015-03-01 19:41 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

Tuesday, 22 September 2009 14:53:48 UTC

Tags



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