如何避免在AutoFixture中使用全局自定义

问题描述 投票:0回答:1

我正在尝试使用

ISpecimenBuilder
:

创建一个对象
var fixture= new Fixture();
fixture.Customizations.Add(new SkipNonPrimitiveMembersCustomization());

var person= fixture.Create<Person>(); // works as expected
var node = fixture.Create<Node>(); // only primitive type properties are set

这不是我想要的节点对象。所以我用

FromFactory
方法绑起来:

var fixture = new Fixture();
var node = fixture.Build<Node>()
            .FromFactory(new SkipNonPrimitiveMembersCustomization())
            .Create();

我得到了:

消息:AutoFixture.ObjectCreationException:装饰后的 ISpecimenBuilder 无法根据请求创建样本:SkipNonPrimitiveMembersCustomizationTests+Node。如果请求表示接口或抽象类,则可能会发生这种情况;如果是这种情况,请注册一个 ISpecimenBuilder,它可以根据请求创建样本。如果这种情况发生在强类型构建表达式中,请尝试使用 IFactoryComposer 方法之一提供工厂。

堆栈跟踪: 
NoSpecimenOutputGuard.Create(对象请求,ISpecimenContext 上下文)
Postprocessor1.Create(对象请求,ISpecimenContext 上下文) CompositeSpecimenBuilder.Create(对象请求,ISpecimenContext 上下文)
FilteringSpecimenBuilder.Create(对象请求,ISpecimenContext上下文)
NodeComposer1.Create(对象请求,ISpecimenContext 上下文) CompositeSpecimenBuilder.Create(对象请求,ISpecimenContext 上下文)
RecursionGuard.Create(对象请求,ISpecimenContext 上下文) CompositeNodeComposer1.Create(对象请求,ISpecimenContext上下文)
SpecimenContext.Resolve(对象请求) SeedIgnoringRelay.Create(对象请求,ISpecimenContext 上下文) CompositeSpecimenBuilder.Create(对象请求,ISpecimenContext 上下文)
FilteringSpecimenBuilder.Create(对象请求,ISpecimenContext上下文)
NodeComposer`1.Create(对象请求,ISpecimenContext上下文) CompositeSpecimenBuilder.Create(对象请求,ISpecimenContext 上下文) RecursionGuard.Create(对象请求,ISpecimenContext上下文)
CompositeNodeComposer1.Create(对象请求,ISpecimenContext上下文)
SpecimenContext.Resolve(对象请求)
SpecimenFactory.Create[T](ISpecimenContext 上下文)
SpecimenFactory.Create[T](ISpecimenBuilder 构建器)
SpecimenFactory.Create[T](IPostprocessComposer1 作曲家)

我的

SpecimenBuilder

public class SkipNonPrimitiveMembersCustomization : ISpecimenBuilder
{
    public object Create(object request, ISpecimenContext context)
    {
        if (request is PropertyInfo propInfo && propInfo != null && !IsPrimitiveType(propInfo.PropertyType))
            return new OmitSpecimen();

        return new NoSpecimen();
    }

    private static bool IsPrimitiveType(Type type)
    {
        if (type is null) return false;

        return type.IsPrimitive ||
            type.IsValueType ||
            type == typeof(string) ||
            // handle arrays of primitive types
            type.IsArray && IsPrimitiveType(type.GetElementType()) == true ||
            type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>) && type.GenericTypeArguments.All(IsPrimitiveType) ||
            // type is a generic type with value type arguments that are all also primitive types
            type.GetGenericArguments().Any(t => t.IsValueType && IsPrimitiveType(t));
    }
}

private class Node
{
    public string Name { get; set; }
    public int Id { get; set; }
    public string[] Tags { get; set; }
    public TestEnum? TestEnum { get; set; }
    public DateTime? CreatedAt { get; set; }
    public Node[] Children { get; set; }
}

顺便说一句,我知道我需要在最后避免循环引用:

fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList()
    .ForEach(b => _fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior());
c# customization autofixture
1个回答
0
投票

首先,我会尝试将一些条件放在括号中以将它们正确分组:

private static bool IsPrimitiveType(Type type)
{
    if (type is null) return false;

    return type.IsPrimitive ||
        type.IsValueType ||
        type == typeof(string) ||
        // handle arrays of primitive types
        (type.IsArray && IsPrimitiveType(type.GetElementType()) == true) ||
        (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>) && type.GenericTypeArguments.All(IsPrimitiveType)) ||
        // type is a generic type with value type arguments that are all also primitive types
        type.GetGenericArguments().Any(t => t.IsValueType && IsPrimitiveType(t));
}

第二件事是你检查

!IsPrimitiveType(propInfo.PropertyType)
,这与你想要的相反,我认为,更正版本:

public object Create(object request, ISpecimenContext context)
{
    if (request is PropertyInfo propInfo && propInfo != null && IsPrimitiveType(propInfo.PropertyType))
        return new OmitSpecimen();

    return new NoSpecimen();
}

经过这些更正后,您的示例按预期工作。

© www.soinside.com 2019 - 2024. All rights reserved.