如何添加自定义后应用的常见后处理

时间:2014-02-04 22:28:37

标签: c# autofixture

我为我的模型定义了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而我的后期处理器应该使用已经创建的标本并填充其一些属性。

3 个答案:

答案 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方法,直到其中一个提供样本。此时,请求被视为满足,其余构建器将被忽略。

     

来源:AutoFixture Documentation