Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
753 views
in Technique[技术] by (71.8m points)

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

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";
        }
    }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...