我为我的模型定义了ISpecimenBuilder并使用它:
new Fixture().Customize(new ModelCustomization());
我想在大多数关于模型的测试中使用它。我还想在我的一个测试类中应用某种形式的后处理。具体来说,我想填充所有创建的CompanyHistory
的属性Offers
。感觉好像可以这样做:
fixture.Build<Offer>()
.With(o => o.CompanyHistory, _previouslyCreatedCompanyHistory)
.Create();
但Build<T>
禁用所有自定义设置,我需要它们。
我可以这样做吗?
fixture.Build<Offer>()
.WithCustomization(new ModelCustomization()) // there is no such method, but i'd like it to be
.With(o => o.CompanyHistory, _previouslyCreatedCompanyHistory)
.Create();
或者我应该写自己的行为?如果是这样,有人可以为我提供这方面的指导吗?
修改: 我觉得我必须强调我想使用我的常用自定义(ModelCustomization)和后处理器
编辑2 :
我从一开始就意味着ModelCustomization
可以(并且应该)创建Offer
而我的后期处理器应该使用已经创建的标本并填充其一些属性。
答案 0 :(得分:5)
以下是在这种情况下您可以创建和使用Postprocessor
的方法:
[Fact]
public void Test()
{
var fixture = new Fixture();
// (You may also include other customizations here.)
fixture.Customizations.Add(
new FilteringSpecimenBuilder(
new Postprocessor(
new MethodInvoker(
new ModestConstructorQuery()),
new OfferFiller()),
new OfferSpecification()));
var offer = fixture.Create<Offer>();
// -> offer.CompanyHistory has the value supplied in OfferFiller command.
}
OfferFiller
命令定义为:
internal class OfferFiller : ISpecimenCommand
{
public void Execute(object specimen, ISpecimenContext context)
{
if (specimen == null)
throw new ArgumentNullException("specimen");
if (context == null)
throw new ArgumentNullException("context");
var offer = specimen as Offer;
if (offer == null)
throw new ArgumentException(
"The specimen must be an instance of Offer.",
"specimen");
Array.ForEach(offer.GetType().GetProperties(), x =>
{
if (x.Name == "CompanyHistory ")
x.SetValue(offer, /*value*/);
else
x.SetValue(offer, context.Resolve(x.PropertyType));
});
}
}
OfferSpecification
定义为:
internal class OfferSpecification : IRequestSpecification
{
public bool IsSatisfiedBy(object request)
{
var requestType = request as Type;
if (requestType == null)
return false;
return typeof(Offer).IsAssignableFrom(requestType);
}
}
答案 1 :(得分:1)
我遇到了类似的问题并尝试过这里提到的解决方案,但是它们没有按预期工作。最后,我找到了PostProcessWhereIsACustomization类的实现,它正是我所需要的:
AutoFixture自定义允许插入任意后处理逻辑a自定义(c =&gt; c.Do())但以全局方式修改为v3(最初为v2)
可以为某人留下一些谷歌搜索。
答案 2 :(得分:0)
我最后写了以下定制:
private class OfferWithCompanyModelCustomization: ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(new FilteringSpecimenBuilder(new Postprocessor(
new ModelSpecimenBuilder(), new FillModelPropertiesCommand()), new ExactTypeSpecification(typeof(Offer))));
}
private class FillModelPropertiesCommand : ISpecimenCommand
{
public void Execute(object specimen, ISpecimenContext context)
{
var offer = specimen as Offer;
offer.CompanyHistory = (CompanyHistory)context.Resolve(typeof(CompanyHistory));
}
}
}
这有效,但它远非完美。正如您所看到的,我直接引用ModelSpecimenBuilder
,因此我依赖于实现(作为后处理器我不喜欢)。
@Nikos发布的答案并不令人满意,因为他的定制忽略了之前在责任链中的定制。
当我们调用Create方法时,CompositeSpecimenBuilder将调用其所有包含的构建器的Create方法,直到其中一个提供样本。此时,请求被视为满足,其余构建器将被忽略。