Search code examples
c#autofixture

Chaining Customizations with Autofixture


I know that Autofixture stops building object when it finds ISpecimenBuilder which can satisfy the request. So when I apply several consequent customizations, all but the last one get ignored. How do I combine the customizations instead? In other words, how do I modify this snippet:

fixture.Customize<SomeClass>(ob => ob.With(x => x.Id, 123)); // this customization is ignored
fixture.Customize<SomeClass>(ob => ob.With(x => x.Rev, 4341)); // only this one takes place

To be equivalent with this snippet:

fixture.Customize<SomeClass>(ob => ob
    .With(x => x.Id, 123)
    .With(x => x.Rev, 4341)); // both customization are applied

Solution

  • Here is what I came up with:

    public class CustomFixture : Fixture
    {
        public CustomFixture ()
        {
            this.Inject(this);
        }
    
        private readonly List<object> _transformations = new List<object>();
    
        public void DelayedCustomize<T>(Func<ICustomizationComposer<T>, ISpecimenBuilder> composerTransformation)
        {
            this._transformations.Add(composerTransformation);
        }
    
        public void ApplyCustomize<T>()
        {
            this.Customize<T>(ob =>
            {
                return this._transformations.OfType<Func<ICustomizationComposer<T>, ISpecimenBuilder>>()
                    .Aggregate(ob, (current, transformation) => (ICustomizationComposer<T>)transformation(current));
            });
        }
    
    }
    

    And the usage:

    var fixture = new CustomFixture();
    
    fixture.DelayedCustomize<SomeClass>(ob => ob.With(x => x.Id, 123)); 
    fixture.DelayedCustomize<SomeClass>(ob => ob.With(x => x.Rev, 4341)); 
    fixture.ApplyCustomize<SomeClass>();
    
    var obj = fixture.Create<SomeClass>();
    // obj.Id == 123
    // obj.Rev == 4341
    

    Not ideal because of the need of ApplyCustomize.