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

前端 未结 3 1513
自闭症患者
自闭症患者 2020-12-11 02:29

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 look

相关标签:
3条回答
  • 2020-12-11 02:58

    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();
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-11 03:01

    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.

    0 讨论(0)
  • 2020-12-11 03:05

    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());
        }
    }
    
    0 讨论(0)
提交回复
热议问题