3

I have an Entity class that exposes a read-only Id property. This property gets set via an ORM after it is saved (no longer transient). I'd like to have AutoFixture call a method that sets the Id property internally for all instances of classes that inherit from Entity.

There are several customizations being applied to the fixture that register the creation of a select few of these descendants, so I'd like to ensure they run first. I guess the ideal situation would be to allow me to run some modification code to an anonymous value before it is returned from the fixture.

For example, when I call fixture.CreateAnonymous<Order>(), there would be some other customization (or the like) that can modify that Order instance before it is returned.

This modification would not intercept just Order, but any Entity descendant.

ventaur
  • 1,821
  • 11
  • 24
  • 1
    [This question/answer](http://stackoverflow.com/a/11657881/11635) is tangentially related (Or you can VTC if you reckon this is too close to that - I'm not sure myself) – Ruben Bartelink Oct 30 '12 at 22:50
  • Since I wanted to run a Postprocessor on all ISpecimenBuilders in the fixture, I hijacked the fixture. – ventaur Oct 31 '12 at 19:52

1 Answers1

3

After solving this with a custom class that extended Fixture, I took the advice of both Ruben and Mark. I created the same basic solution via an ICustomization that is applied via my existing custom CompositeCustomization. Here is the new customization for setting my entity Ids before instances are returned via CreateAnonymous.

public class SetEntityIdCustomization : ICustomization {
    public void Customize(IFixture fixture) {
        var engine = ((Fixture)fixture).Engine;
        fixture.Customizations.Add(new Postprocessor(
            engine, o => {
                var entity = o as BaseEntity;
                if (entity == null || !entity.IsTransient()) {
                    return;
                }

                entity.SetId(fixture.CreateAnonymous<Guid>());
            }));
    }
}
arcain
  • 14,920
  • 6
  • 55
  • 75
ventaur
  • 1,821
  • 11
  • 24
  • 2
    Cool. Only thing I'd personally do is extract that as an `ICustomization` in order to be able to apply them individually and give the behavior an Intention Revealing Name but obviously that's functionally equivalent to what you have for long as you continue to have just one Customization in your suite. – Ruben Bartelink Oct 31 '12 at 21:00
  • I have quite a few Customizations being applied by a AutoDataAttribute (XUnit) via a CompositeCustomization. The reason I chose this route, instead of another Customization, was to ensure that my Postprocessor is applied after all other Customizations (some of them are used to actually create an entity). Thanks! – ventaur Nov 01 '12 at 12:10
  • Interesting. Sounds like this aint your first battle with AF so! – Ruben Bartelink Nov 01 '12 at 14:51
  • True, but I do love the library. Big time saver overall. – ventaur Nov 01 '12 at 19:35
  • Wasnt suggesting anything bad about The Library(s) for a second - it really allows you to push he expressiveness and brevity of your tests to the max. Was just saying "I won't be bothering you with beginner suggestions anymore" ! – Ruben Bartelink Nov 01 '12 at 23:48
  • Understood. Let me tell you though, I had to put my head down and really think about some stuff to get the absolute crazy coolness I'm getting out of AF now. Of course, being made to really think about your testing is absolutely a good thing. Thanks again! – ventaur Nov 02 '12 at 20:20
  • 1
    That looks like a great solution - much simpler that something I had in mind :) FWIW, I want to second Ruben Bartelink's suggestion about refactoring into an ICustomization. You can easily control the ordering: http://blog.ploeh.dk/2012/07/31/TheOrderOfAutoFixtureCustomizationsMatter.aspx This would also allow you to use a Fixture instance to create the value passed to `SetId`. – Mark Seemann Nov 03 '12 at 15:28
  • Thanks for the info, Mark. I've read the article you linked to numerous times (before and again now). I still do not see how to use an ICustomization to modify an instance that will be returned from a later call to CreateAnonymous. Unless, this is a perfect use for something like `fixture.Do(entity => entity.SetId(fixture.CreateAnonymous()))`. I've not used Do much. Perhaps, I'll just try it and update here with my results. ;-) – ventaur Nov 04 '12 at 02:29
  • Okay, so `Do` didn't quite work out. However, I did manage to use an ICustomization that uses the code from my original solution. I've updated the answer. – ventaur Nov 04 '12 at 03:24