使用FromSeed自定义AutoFixure会导致异常

时间:2015-11-10 16:39:29

标签: c# unit-testing autofixture

鉴于这两个类:

RecyclerView

我已经设置了以下测试:

class Foo
{
    ...
}

class Bar
{
    public Foo FooBar { get; set; }
}

我可以使用和不使用种子值直接创建void Test() { var fixture = new Fixture(); fixture.Customize<Foo>(x => x.FromSeed(TestFooFactory)); var fooWithoutSeed = fixture.Create<Foo>(); var fooWithSeed = fixture.Create<Foo>(new Foo()); var bar = fixture.Create<Bar>(); //error occurs here } Foo TestFooFactory(Foo seed) { //do something with seed... return new Foo(); } 个对象而没有任何问题。但是,一旦我尝试创建具有Foo属性的Bar对象,我就会得到Foo

  

装饰的ISpecimenBuilder无法根据请求创建样本:Foo。如果请求表示接口或抽象类,则会发生这种情况;如果是这种情况,请注册一个可以根据请求创建标本的ISpecimenBuilder。如果在强类型的Build表达式中发生这种情况,请尝试使用其中一个IFactoryComposer方法提供工厂。

我希望ObjectCreationException在创建TestFooFactory期间传递null种子值,就像我创建没有种子值的Bar一样。我做错了什么,或者这可能是个错误?

在我的真实场景中,我想自定义当我传入种子值时,AutoFixture如何使用某些对象的种子值,但如果没有提供种子,我仍然希望AutoFixture默认为正常行为。

1 个答案:

答案 0 :(得分:5)

您自定义Fixture以使用种子值is correct的方式。

您看到的行为是FromSeed自定义修改AutoFixture管道的结果。如果您有兴趣阅读详细信息,我已将其描述为here

作为一种解决方法,您可以使用自定义样本构建器来处理这样的种子请求:

public class RelaxedSeededFactory<T> : ISpecimenBuilder
{
    private readonly Func<T, T> create;

    public RelaxedSeededFactory(Func<T, T> factory)
    {
        this.create = factory;
    }

    public object Create(object request, ISpecimenContext context)
    {
        if (request != null && request.Equals(typeof(T)))
        {
            return this.create(default(T));
        }

        var seededRequest = request as SeededRequest;

        if (seededRequest == null)
        {
            return new NoSpecimen(request);
        }

        if (!seededRequest.Request.Equals(typeof(T)))
        {
            return new NoSpecimen(request);
        }

        if ((seededRequest.Seed != null)
            && !(seededRequest.Seed is T))
        {
            return new NoSpecimen(request);
        }

        var seed = (T)seededRequest.Seed;

        return this.create(seed);
    }
}

然后,您可以使用它来创建类型为Foo的对象:

fixture.Customize<Foo>(c => c.FromFactory(
    new RelaxedSeededFactory<Foo>(TestFooFactory)));

此自定义将在填充default(Foo)类型的属性时将null - 即TestFooFactory - 作为Foo工厂函数的种子传递。