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

Nat*_*n A 5 c# unit-testing autofixture

鉴于这两个类:

class Foo
{
    ...
}

class Bar
{
    public Foo FooBar { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我已经设置了以下测试:

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();
}
Run Code Online (Sandbox Code Playgroud)

我可以Foo使用和不使用种子值直接创建对象而没有任何问题.但是一旦我尝试创建一个Bar具有Foo属性的对象,我得到一个ObjectCreationException:

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

我期望在创建过程中TestFooFactory传递null种子值Bar,就像我在Foo没有种子值的情况下创建时一样.我做错了什么,或者这可能是一个错误?

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

Enr*_*lio 5

您自定义Fixture使用种子值的方式是正确的.

您所看到的行为是FromSeed自定义如何修改AutoFixture管道的结果.如果你有兴趣阅读细节,我在这里描述它们.

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

fixture.Customize<Foo>(c => c.FromFactory(
    new RelaxedSeededFactory<Foo>(TestFooFactory)));
Run Code Online (Sandbox Code Playgroud)

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

  • 我用_better_方法更新了自定义的`RelaxedSeededFactory`样本构建器.它不会处理所有请求,而只处理`T`的种子和非种子请求. (2认同)