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"; } } ```