How do I use Autofixture (v3) with ICustomization, ISpecimenBuilder to deal with constructor parameter?

autofixture, unit-testing

Solution

Solution 1:

Register that the `Color` writable property should not be assigned any automatic value as part of the post-processing:

internal class LeafColorCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customize<Leaf>(c => c
            .Without(x => x.Color));

        fixture.Customizations.Add(new LeafBuilder());
    }
}

Solution 2:

Make the `Color` property read-only:

public class Leaf
{
    private readonly string color;

    public Leaf(string color)
    {
        if (color != "brown")
            throw new ArgumentException(@"NO LEAF FOR YOU!");

        this.color = color;
    }

    public string Color
    {
        get { return this.color; }
    }
}

Since the `Color` property is read-only AutoFixture is not going to assign a value for it.

The above solutions apply also to AutoFixture 2.

Problem

I'm trying to overcome a scenario in which a class has a string constructor parameter which cannot be satisfied by any old string generated by Autofixture (the Guid-y looking value). Before you're tempted to answer simply with a link to Mark Seemann's Ploeh blog entry on Convention-based Customizations, let me say that I've been referencing it and other blog entries of his for this test, which I can't get to pass. When I step through in debug, I can see that at some point the constructor parameter is passed in with the valid value, but the test still fails with the Guid-y Color value. I think this has something to do with the fact that there is both a 'color' parameter value, and a 'Color' property to be populated by Autofixture. Is it that I've written an ISpecimenBuilder that addresses the constructor parameter, but I'm testing the public property value (two different things)? I know that all this is overkill for the example, but I envision a more complicated scenario in which using the `Build<T>().With()` method would not be DRY. The Failing Test ``` [Fact] public void Leaf_Color_Is_Brown() { // arrange var fixture = new Fixture().Customize(new LeafColorCustomization()); // act var leaf = fixture.Create<Leaf>(); // using .Build<>.With(), test passes //var leaf = fixture.Build<Leaf>().With(l => l.Color, "brown").CreateAnonymous(); // assert Assert.True(leaf.Color == "brown"); } ``` The SUT ``` public class Leaf { public Leaf(string color) { if (color != "brown") throw new ArgumentException(@"NO LEAF FOR YOU!"); this.Color = color; } public string Color { get; set; } } ``` The CompositeCustomization implementation (I know the AutoMoqCustomization() isn't needed in this example) ``` public class LeafCustomization : CompositeCustomization { public LeafCustomization() : base( new LeafColorCustomization(), new AutoMoqCustomization()) { } } ``` The Leaf-specific ICustomization ``` public class LeafColorCustomization : ICustomization { public void Customize(IFixture fixture) { if (fixture == null) throw new ArgumentNullException("fixture"); fixture.Customizations.Add(new LeafBuilder()); } } ``` The String-constructor-with-name-of-Color-specific ISpecimenBuilder ``` public class LeafBuilder : ISpecimenBuilder { public object Create(object request, ISpecimenContext context) { var pi = request as ParameterInfo; if (pi == null) return new NoSpecimen(request); if (pi.ParameterType != typeof(string) || pi.Name != "color") return new NoSpecimen(request); return "brown"; } } ```

Original source