如何将自定义ISpecimenBuilder
实例与我想要全局应用的OmitOnRecursionBehavior
一起用于所有夹具创建的对象?
我正在使用带有恶臭循环引用的EF Code First模型,出于此问题的目的,无法消除:
public class Parent {
public string Name { get; set; }
public int Age { get; set; }
public virtual Child Child { get; set; }
}
public class Child {
public string Name { get; set; }
public int Age { get; set; }
public virtual Parent Parent { get; set; }
}
我熟悉侧步循环引用的技术,就像在这个通过测试中一样:
[Theory, AutoData]
public void CanCreatePatientGraphWithAutoFixtureManually(Fixture fixture)
{
//fixture.Customizations.Add(new ParentSpecimenBuilder());
//fixture.Customizations.Add(new ChildSpecimenBuilder());
fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior());
fixture.Behaviors.Add(new TracingBehavior());
var parent = fixture.Create<Parent>();
parent.Should().NotBeNull();
parent.Child.Should().NotBeNull();
parent.Child.Parent.Should().BeNull();
}
但如果其中一个/两个自定义都被取消注释,我会得到一个例外:
System.InvalidCastException: Unable to cast object of type
'Ploeh.AutoFixture.Kernel.OmitSpecimen' to type 'CircularReference.Parent'.
当我致电ISpecimenBuilder
以解决ISpecimenContext
并且请求来自{{}时,我的Parent
实施(在此问题的底部显示)中发生了失败的广告{1}}正在解决。我可以防范来自Child
解析操作的请求,如下所示:
Child
但是,这似乎污染了//...
&& propertyInfo.ReflectedType != typeof(Child)
//...
实施,知道'谁'可能正在提出请求。此外,它似乎复制了“全局”ISpecimenBuilder
的目的。
我想使用OmitOnRecursionBehavior
实例,因为除了处理循环引用之外,还有其他事情要自定义。我花了很多时间在SO上和Ploeh上查找这样的场景示例,但我还没有找到任何讨论行为和自定义组合的内容。重要的是,解决方案是我可以用ISpecimenBuilder
封装的,而不是
ICustomization
...因为最终我想为测试扩展//...
fixture.ActLikeThis(new SpecialBehavior())
.WhenGiven(typeof (Parent))
.AndDoNotEvenThinkAboutBuilding(typeof(Child))
.UnlessParentIsNull()
//...
属性。
以下是我的[AutoData]
实施以及失败测试的ISpecimenBuilder
输出:
TracingBehavior
答案 0 :(得分:4)
是否可以使用Customize
方法自定义创建算法?
如果是,您可以创建并使用以下[ParentChildConventions]
属性:
internal class ParentChildConventionsAttribute : AutoDataAttribute
{
internal ParentChildConventionsAttribute()
: base(new Fixture().Customize(new ParentChildCustomization()))
{
}
}
internal class ParentChildCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<Child>(c => c
.With(x => x.Name,
fixture.Create<string>().ToLowerInvariant())
.With(x => x.Age,
Math.Min(17, fixture.Create<int>()))
.Without(x => x.Parent));
fixture.Customize<Parent>(c => c
.With(x => x.Name,
fixture.Create<string>().ToUpperInvariant())
.With(x => x.Age,
Math.Min(18, fixture.Create<int>())));
}
}
原始测试使用[ParentChildConventions]
属性传递:
[Theory, ParentChildConventions]
public void CanCreatePatientGraphWithAutoFixtureManually(
Parent parent)
{
parent.Should().NotBeNull();
parent.Child.Should().NotBeNull();
parent.Child.Parent.Should().BeNull();
}
答案 1 :(得分:1)
您也可以使用AutoFixture.AutoEntityFramework来帮助EF。