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

孤街醉人 提交于 2019-11-28 12:04:33
Nikos Baxevanis

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.

Assuming you deal with the property setting stuff separately, here's a constructor argument restriction Customization which does the trick:

class BrownLeavesCustomization : ICustomization
{
    void ICustomization.Customize( IFixture fixture )
    {
        Func<string> notBrownGenerator = fixture.Create<Generator<string>>()
            .SkipWhile( x => x == "Brown" )
            .First;
        fixture.Customizations.Add( 
            ArgumentGeneratorCustomization<Leaf>.ForConstructorArgument(
                "color", 
                notBrownGenerator ) );
    }

    static class ArgumentGeneratorCustomization<T>
    {
        public static ISpecimenBuilder ForConstructorArgument<TArg>( string argumentName, Func<TArg> generator )
        {
            return new ConstructorArgumentGenerator<TArg>( argumentName, generator );
        }

        class ConstructorArgumentGenerator<TArg> : ISpecimenBuilder
        {
            readonly string _argumentName;
            readonly Func<TArg> _generator;

            public ConstructorArgumentGenerator( string argumentName, Func<TArg> generator )
            {
                Assert.Contains( argumentName, from ctor in typeof( T ).GetConstructors() from param in ctor.GetParameters() select param.Name );
                _argumentName = argumentName;
                _generator = generator;
            }

            object ISpecimenBuilder.Create( object request, ISpecimenContext context )
            {
                var pi = request as ParameterInfo;
                if ( pi == null )
                    return new NoSpecimen( request );
                if ( pi.Member.DeclaringType != typeof( T ) )
                    return new NoSpecimen( request );
                if ( pi.Member.MemberType != MemberTypes.Constructor )
                    return new NoSpecimen( request );
                if ( pi.ParameterType != typeof( TArg ) )
                    return new NoSpecimen( request );
                if ( pi.Name != _argumentName )
                    return new NoSpecimen( request );

                return _generator();
            }
        }
    }
}
Jeff

Solution: (based on Mark Seemann's comment on this answer)

Accommodate both the constructor parameter and the writeable property in the ISpecimenBuilder implementation, and do nothing other than add the LeafBuilder instance in LeafColorCustomization:

public class LeafBuilder : ISpecimenBuilder
{
    public object Create(object request, ISpecimenContext context)
    {
        var paramInfo = request as ParameterInfo;
        if (paramInfo != null
            && paramInfo.ParameterType == typeof(string)
            && paramInfo.Name == "color")
        { return "brown"; }

        var propInfo = request as PropertyInfo;
        if (propInfo != null
            && propInfo.PropertyType == typeof(string)
            && propInfo.Name == "Color")
        { return "brown"; }

        return new NoSpecimen(request);
    }
}

internal class LeafColorCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customizations.Add(new LeafBuilder());
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!