忽略Autofixture中所有实现的基类属性

时间:2018-04-04 09:26:11

标签: autofixture

我的课程如下:

public class BaseItem
{
    public Guid Id { get; set; }

    public Language Language { get; set; }
}

public class ItemA : BaseItem
{
    public string Name { get; set; }
}

public class ItemB : BaseItem
{
    public string Path { get; set; }
}

每次创建LanguageItemAItemB类的任何未来实现时,我都想省略属性BaseItem

我在自定义类中添加了这一行(下面),但在生成ItemA / ItemB时, AutoFixture 仍尝试生成Language属性

fixture.Register<BaseItem>(() => { return fixture.Build<BaseItem>().Without(i => i.Language).Create(); });

在这样的实现类级别上省略属性(见下文)是有效的。

fixture.Register<ItemA>(() => { return fixture.Build<ItemA>().Without(i => i.Language).Create(); });

我的问题是:

  1. 如何实现这样做的通用方法,以便我不必自定义每个实现类?
  2. 如果有办法做#1,如果我希望为某些例外生成语言属性,我怎样才能覆盖它?

1 个答案:

答案 0 :(得分:0)

Q1

为了定位(或者更确切地说,省略)在基类上定义的属性,我知道没有比定义自定义ISpecimenBuilder更好的方法,在这种情况下类似于:

public class OmitLanguageBuilder : ISpecimenBuilder
{
    public object Create(object request, ISpecimenContext context)
    {
        var pi = request as PropertyInfo;
        if (pi != null &&
            pi.PropertyType == typeof(Language)
            && pi.Name == "Language"
            && pi.DeclaringType == typeof(BaseItem))
            return new OmitSpecimen();

        return new NoSpecimen();
    }
}

这专门处理仅在Language上声明的BaseItem属性的请求。如果您想要不那么具体,可以删除if表达式中的一些谓词。当AutoFixture收到这样的请求时,它会解释特殊的信号类型&#39; OmitSpecimen作为忽略该财产的指示。

您可以直接向OmitLanguageBuilder实例注册Fixture(尽管您应该将其打包在 Customization 中。此测试通过:

[Fact]
public void Q1A()
{
    var fixture = new Fixture();
    fixture.Customizations.Add(new OmitLanguageBuilder());

    var actual = fixture.Create<ItemA>();

    Assert.Null(actual.Language);
    Assert.NotEqual(default(Guid), actual.Id);
    Assert.NotNull(actual.Name);
}

ItemB的类似测试也会通过。

Q2

如果要在特殊测试用例中填充Language,最简单的解决方案可能只是在事实之后填充它:

[Fact]
public void Q2SetAfter()
{
    var fixture = new Fixture();
    fixture.Customizations.Add(new OmitLanguageBuilder());

    var actual = fixture.Create<ItemA>();
    actual.Language = fixture.Create<Language>();

    Assert.NotNull(actual.Language);
    Assert.NotEqual(default(Guid), actual.Id);
    Assert.NotNull(actual.Name);
}

另一种选择是使用Build API:

[Fact]
public void Q2Build()
{
    var fixture = new Fixture();
    fixture.Customizations.Add(new OmitLanguageBuilder());

    var actual = 
        fixture.Build<ItemA>().With(x => x.Language, fixture.Create<Language>()).Create();

    Assert.NotNull(actual.Language);
    Assert.NotEqual(default(Guid), actual.Id);
    Assert.NotNull(actual.Name);
}

最后,如果您需要更改AutoFixture处理类型的方式,您可以执行以下操作:

[Fact]
public void Q2Customize()
{
    var fixture = new Fixture();
    fixture.Customizations.Add(new OmitLanguageBuilder());
    fixture.Customize<ItemA>(c => c.With(x => x.Language, fixture.Create<Language>()));

    var actual = fixture.Create<ItemA>();

    Assert.NotNull(actual.Language);
    Assert.NotEqual(default(Guid), actual.Id);
    Assert.NotNull(actual.Name);
}