Autofixture 声明性自动数据参数的属性集合大小

Collection size from attribute for Autofixture declarative autodata parameter

如何使用 属性 上的属性指定 list/enumerable 的 length/size 使用 Autofixture 的声明性参数样式传递到测试中?

我希望能够在不将参数移入测试主体的情况下使该测试通过。

        [Theory, AutoData]
        public void CollectionSizeTest(
            List<int> defaultSize,
            List<int> customSize,
            List<int> customSize2,
            IEnumerable<string> empty
        )
        {
            Assert.Equal(3, defaultSize.Count);
            Assert.Equal(5, customSize.Count);
            Assert.Equal(6, customSize2.Count);
            Assert.Empty(empty);
        }

您可以为此创建自定义属性,例如 CollectionSizeAttribute:

        [Theory, AutoData]
        public void CollectionSizeTest(
            List<int> defaultSize,
            [CollectionSize(5)] List<int> customSize,
            [CollectionSize(6)] List<int> customSize2,
            [CollectionSize(0)] IEnumerable<string> empty,
            List<string> defaultSize2
        )
        {
            Assert.Equal(3, defaultSize.Count);
            Assert.Equal(5, customSize.Count);
            Assert.Equal(6, customSize2.Count);
            Assert.Empty(empty);
            Assert.Equal(3, defaultSize2.Count);
        }

        public class CollectionSizeAttribute : CustomizeAttribute
        {
            private readonly int _size;

            public CollectionSizeAttribute(int size)
            {
                _size = size;
            }

            public override ICustomization GetCustomization(ParameterInfo parameter)
            {
                if (parameter == null) throw new ArgumentNullException(nameof(parameter));

                var objectType = parameter.ParameterType.GetGenericArguments()[0];

                var isTypeCompatible =
                    parameter.ParameterType.IsGenericType
                    && parameter.ParameterType.GetGenericTypeDefinition().MakeGenericType(objectType).IsAssignableFrom(typeof(List<>).MakeGenericType(objectType))
                ;
                if (!isTypeCompatible)
                {
                    throw new InvalidOperationException($"{nameof(CollectionSizeAttribute)} specified for type incompatible with List: {parameter.ParameterType} {parameter.Name}");
                }

                var customizationType = typeof(CollectionSizeCustomization<>).MakeGenericType(objectType);
                return (ICustomization) Activator.CreateInstance(customizationType, parameter, _size);
            }

            public class CollectionSizeCustomization<T> : ICustomization
            {
                private readonly ParameterInfo _parameter;
                private readonly int _repeatCount;

                public CollectionSizeCustomization(ParameterInfo parameter, int repeatCount)
                {
                    _parameter = parameter;
                    _repeatCount = repeatCount;
                }

                public void Customize(IFixture fixture)
                {
                    fixture.Customizations.Add(new FilteringSpecimenBuilder(
                        new FixedBuilder(fixture.CreateMany<T>(_repeatCount).ToList()),
                        new EqualRequestSpecification(_parameter)
                    ));
                }
            }
        }

这会导致通过调用 fixture.CreateMany<T>(_repeatCount).

将参数创建为具有给定大小的列表