我为我的模型定义了ISpecimenBuilder并使用它:
new Fixture().Customize(new ModelCustomization());
Run Code Online (Sandbox Code Playgroud)
我想在大多数关于模型的测试中使用它.我还想在我的一个测试类中应用某种形式的后处理.具体来说,我想填补CompanyHistory
所有创建的属性Offers
.感觉它可以这样做:
fixture.Build<Offer>()
.With(o => o.CompanyHistory, _previouslyCreatedCompanyHistory)
.Create();
Run Code Online (Sandbox Code Playgroud)
但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();
Run Code Online (Sandbox Code Playgroud)
或者我应该写自己的行为?如果是这样,有人可以为我提供这方面的指导吗?
编辑:我觉得我必须强调我要使用我的常见自定义(ModelCustomization)和后处理器
编辑2:我从一开始就意味着ModelCustomization
可以(并且应该)创建Offer
和我的待处理后处理器应该使用已创建的样本并填充其某些属性.
以下是Postprocessor
在这种情况下如何创建和使用a :
[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.
}
Run Code Online (Sandbox Code Playgroud)
该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));
});
}
}
Run Code Online (Sandbox Code Playgroud)
的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);
}
}
Run Code Online (Sandbox Code Playgroud)
我最终写了以下定制:
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));
}
}
}
Run Code Online (Sandbox Code Playgroud)
这可行,但远非完美。正如您所看到的,我直接引用ModelSpecimenBuilder
,所以我依赖于实现(作为后处理器,我不想成为)。
@Nikos 发布的答案并不令人满意,因为他的定制忽略了责任链中以前的定制。
当我们调用 Create 方法时,CompositeSpecimenBuilder 将调用其包含的所有构建器的 Create 方法,直到其中一个构建器提供样本。此时,请求被认为已得到满足,其余构建器将被忽略。