joozek joozek - 2 months ago 7
C# Question

How can I add common postprocessing applied after customization

I have defined ISpecimenBuilder for my models and use it like that:

new Fixture().Customize(new ModelCustomization());


I want to use it in most of my tests concerning model. I also want to apply some form of post-processing in one of my test classes. Specifically I want to fill property
CompanyHistory
of all created
Offers
. It feels like it could be done like that:

fixture.Build<Offer>()
.With(o => o.CompanyHistory, _previouslyCreatedCompanyHistory)
.Create();


But
Build<T>
disables all customizations and I need them.

Can I do something like that?

fixture.Build<Offer>()
.WithCustomization(new ModelCustomization()) // there is no such method, but i'd like it to be
.With(o => o.CompanyHistory, _previouslyCreatedCompanyHistory)
.Create();


Or should I write my own Behavior? If so, can someone provide me with guidelines on doing that?

EDIT:
I feel I have to stress out that I want to use both my common customization (ModelCustomization) and Postprocessor

EDIT 2:
What I meant from the beginning is that
ModelCustomization
can (and should) create
Offer
and my to-be postprocessor should use that already created specimen and fill some of its properties.

Answer

I ended up writing following Customization:

private class OfferWithCompanyModelCustomization: ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customizations.Add(new FilteringSpecimenBuilder(new Postprocessor(
            new ModelSpecimenBuilder(), new FillModelPropertiesCommand()), new ExactTypeSpecification(typeof(Offer))));
    }

    private class FillModelPropertiesCommand : ISpecimenCommand
    {
        public void Execute(object specimen, ISpecimenContext context)
        {
            var offer = specimen as Offer;
            offer.CompanyHistory = (CompanyHistory)context.Resolve(typeof(CompanyHistory));
        }
    }
}

This works, but it's far from perfect. As you can see, I refer to ModelSpecimenBuilder directly, so I'm dependent on implementation (as postprocessor I'd like not to be).

Answer posted by @Nikos is not satisfying, because his customization ignores previous customizations in chain of responsibility.

When we invoke the Create method, a CompositeSpecimenBuilder will invoke the Create method of all its contained builders until one of them provides a specimen. At this point the request is considered to be satisfied, and the rest of the builders are ignored.

source: AutoFixture Documentation

Comments