仅将自定义 ISpecimenBuilder 注册到特定类型

Register custom ISpecimenBuilder only to a particular type

我有一个用于 AutoFixture 的自定义样本生成器,它根据所请求的 属性 类型省略了对属性中匿名值的请求。

    public class PropertyTypeExclusion<T> : ISpecimenBuilder
    {
        public object Create(object request, ISpecimenContext context)
        {
            var propertyInfo = request as PropertyInfo;

            if (propertyInfo?.PropertyType == typeof(T))
            {
                return new OmitSpecimen();
            }

            return new NoSpecimen();
        }
    }

我可以毫无问题地将自定义添加到夹具,并且按预期工作。

_fixture.Customizations.Add(new PropertyTypeExclusion<IdentityRef>());

现在我希望将此排除项注册到特定类型的请求中。像这样:

_fixture.Customize<Release>(c => new PropertyTypeExclusion<IdentityRef>());

虽然使用 .Customize<Release> 是有效的,但它与调用 .Customizations.Add 的结果相同。

有没有办法将此 ISpecimenBuilder 注册到特定的请求类型?

如果我没理解错的话,你希望能够像这样做:

fixture.Create<Release>();       // the `IdentityRef` prop is omitted
fixture.Create<SomeOtherType>(); // the `IdentityRef` prop is NOT omitted

好的,让我们看一下这个声明:

While the use of .Customize is valid, it has the same outcome as the call to .Customizations.Add

...意味着即使您仅为 Release 类型注册自定义,other 类型也会受到影响:

fixture.Customize<Release>(c => new PropertyTypeExclusion<IdentityRef>());
fixture.Create<Release>();       // the `IdentityRef` prop is omitted which is OK
fixture.Create<SomeOtherType>(); // the `IdentityRef` prop is also omitted but it MUST NOT

对我来说这听起来像是 AF 中的一个错误,我会解决它 here...

作为您问题的快速解决方法,您可以扩展自定义以接受 class 和 属性 类型以执行更精确的过滤:

public class PropertyTypeExclusion<TType, TProp> : ISpecimenBuilder
{
    public object Create(object request, ISpecimenContext context)
    {
        var propertyInfo = request as PropertyInfo;

        if (propertyInfo?.PropertyType == typeof(TProp) &&
            propertyInfo.DeclaringType == typeof(TType))
        {
            return new OmitSpecimen();
        }

        return new NoSpecimen();
    }
}

现在:

fixture.Customizations.Add(new PropertyTypeExclusion<Release, IdentityRef>());
fixture.Create<Release>();       // the `IdentityRef` prop is omitted
fixture.Create<SomeOtherType>(); // the `IdentityRef` prop is NOT omitted

要完全重用现有的 AutoFixture 构建块,您只需创建一个规范即可:

public class PropertyOfTypeSpecification<TContainer, TProperty> : IRequestSpecification
{
    public bool IsSatisfiedBy(object request)
    {
        return request is PropertyInfo propertyInfo
               && propertyInfo.PropertyType == typeof(TProperty)
               && propertyInfo.ReflectedType == typeof(TContainer);
    }
}

稍后您可以按如下方式自定义 Fixture:

var fixture = new Fixture();
fixture.Customizations.Add(
    new Omitter(
        new PropertyOfTypeSpecification<Build, IdentityRef>()));