我正在尝试使用
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());
首先,我会尝试将一些条件放在括号中以将它们正确分组:
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();
}
经过这些更正后,您的示例按预期工作。