使用 FromSeed 自定义 AutoFixure 导致异常
Customizing AutoFixure using FromSeed Causes Exception
给定两个 类:
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
个对象,没有任何问题。但是一旦我尝试创建一个具有 Foo
属性 的 Bar
对象,我就会得到一个 ObjectCreationException
:
The decorated ISpecimenBuilder could not create a specimen based on the request: Foo. This can happen if the request represents an interface or abstract class; if this is the case, register an ISpecimenBuilder that can create specimens based on the request. If this happens in a strongly typed Build expression, try supplying a factory using one of the IFactoryComposer methods.
我希望 TestFooFactory
在创建 Bar
期间传递 null
种子值,就像我创建 Foo
时没有种子值一样。我做错了什么,或者这可能是一个错误?
在我的真实场景中,我想自定义当我传入种子值时 AutoFixture 如何为某些对象使用种子值,但我仍然希望 AutoFixture 在没有提供种子时默认为正常行为。
您自定义 Fixture
以使用种子值的方式 。
您看到的行为是 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)));
当填充 Foo
.[=21= 类型的属性时,此自定义将传递 default(Foo)
– 即 null
– 作为 TestFooFactory
工厂函数的种子]
给定两个 类:
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
个对象,没有任何问题。但是一旦我尝试创建一个具有 Foo
属性 的 Bar
对象,我就会得到一个 ObjectCreationException
:
The decorated ISpecimenBuilder could not create a specimen based on the request: Foo. This can happen if the request represents an interface or abstract class; if this is the case, register an ISpecimenBuilder that can create specimens based on the request. If this happens in a strongly typed Build expression, try supplying a factory using one of the IFactoryComposer methods.
我希望 TestFooFactory
在创建 Bar
期间传递 null
种子值,就像我创建 Foo
时没有种子值一样。我做错了什么,或者这可能是一个错误?
在我的真实场景中,我想自定义当我传入种子值时 AutoFixture 如何为某些对象使用种子值,但我仍然希望 AutoFixture 在没有提供种子时默认为正常行为。
您自定义 Fixture
以使用种子值的方式
您看到的行为是 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)));
当填充 Foo
.[=21= 类型的属性时,此自定义将传递 default(Foo)
– 即 null
– 作为 TestFooFactory
工厂函数的种子]