为什么在使用样本生成器时会得到循环引用 DummyApiController --> DummyApiController?
Why do I get a circular reference DummyApiController --> DummyApiController when using a specimen builder?
我正在尝试使用 AutoFixture (3.50.6) 生成 ApiController (WebAPI 2) 的一些子类。
我自定义了 AF 以允许使用 this customization 生成 ApiController。
由于进一步的定制需求,我想创建一个 SpecimenBuilder
来创建任何类型的 ApiController 并使用简单的
应用此配置
fixture.Create<DummyController>();
我试过这个测试 (NUnit 3) :
[TestFixture]
public class ApiControllerSpecimenBuilderTests
{
[Test]
public void ShouldCreateAControllerUsingSpecimenBuilder()
{
var fixture = new Fixture()
.Customize(new AutoMoqCustomization())
.Customize(new ApiControllerCustomization());
fixture.Customizations.Add(new ApiControllerSpecimenBuilder());
var ctl = fixture.Create<DummyController>();
}
}
public class ApiControllerCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Inject(new UriScheme("http"));
fixture.Customize<HttpConfiguration>(c => c
.OmitAutoProperties());
fixture.Customize<HttpRequestMessage>(c => c
.Do(x =>
x.Properties.Add(
HttpPropertyKeys.HttpConfigurationKey,
fixture.Create<HttpConfiguration>())));
fixture.Customize<HttpRequestContext>(c => c
.Without(x => x.ClientCertificate));
}
}
public class ApiControllerSpecimenBuilder : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
var t = request as Type;
if (t == null || !typeof(ApiController).IsAssignableFrom(t))
{
return new NoSpecimen();
}
var controller = context.Resolve(t) as ApiController;
// ...
return controller;
}
}
public class DummyController : ApiController
{
}
失败并出现以下错误:
Ploeh.AutoFixture.ObjectCreationException : AutoFixture was unable to
create an instance of type System.RuntimeType because the traversed
object graph contains a circular reference. [...]
Path: Foo.Common.Tests.AutoFixture.SpecimenBuilders.DummyController
--> Foo.Common.Tests.AutoFixture.SpecimenBuilders.DummyController
为什么 DummyController 有对其自身类型的引用?
此外,如果我用 DummyController 的空自定义更改测试,它会通过:
[Test]
public void ShouldCreateAControllerUsingSpecimenBuilder()
{
var fixture = new Fixture()
.Customize(new AutoMoqCustomization())
.Customize(new ApiControllerCustomization())
.Customize(new DummyControllerCustomization()); // new customization
fixture.Customizations.Add(new ApiControllerSpecimenBuilder());
var ctl = fixture.Create<DummyController>();
}
public class DummyControllerCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<DummyController>(c => c);
}
}
在这种情况下,SpecimenBuilder 似乎不再受 DummyController 类型的影响。这个空的定制做了什么使测试通过?它会覆盖样本生成器吗?但是为什么它不抛出同样的异常,因为我没有告诉他省略任何东西(无论如何,我不知道要省略什么...)?
我想我可以使用 OmitOnRecursionBehavior
,但我想保留默认行为以避免在所有其他情况下递归,而且我更愿意了解正在发生的事情(或者如果我这样做了smth 真的很愚蠢)。
只需删除 ApiControllerSpecimenBuilder
:
[TestFixture]
public class ApiControllerSpecimenBuilderTests
{
[Test]
public void ShouldCreateAControllerUsingSpecimenBuilder()
{
var fixture = new Fixture()
.Customize(new AutoMoqCustomization())
.Customize(new ApiControllerCustomization());
//fixture.Customizations.Add(new ApiControllerSpecimenBuilder());
var ctl = fixture.Create<DummyController>();
}
}
以上版本的测试通过(在我的机器上)。
问题是ApiControllerSpecimenBuilder
如果通过初始保护子句就进入无限递归:
var controller = context.Resolve(t) as ApiController;
调用context.Resolve(t)
进入新对象创建'session'。 AutoFixture 询问其树中的每个 ISpecimenBuilder
是否可以处理 t
的请求。当它到达 ApiControllerSpecimenBuilder
时,它会再次调用 context.Resolve(t)
进行响应,如此循环往复。
您不需要自己做任何这些工作,因为 AutoFixture 已经完全能够为您创建 ApiController
个实例(只要 ApiControllerCustomization
到位)。
如果我正确理解了整个用例,但是,实际要求是您希望在创建 AutoFixture 后对 ApiController
实例进行某种 post 处理适合你的对象。
这种情况的一般解决方案是使用 Postprocessor
或 Postprocessor<T>
,但有时可能需要一些时间才能正确处理。通常,有更简单的方法可以实现您想要做的事情。
如果您需要这方面的帮助,请提出另一个问题。下次你不需要悬赏,因为我通常会监控 autofixture 标签。这个问题不知何故没有引起我的注意。抱歉!
我正在尝试使用 AutoFixture (3.50.6) 生成 ApiController (WebAPI 2) 的一些子类。
我自定义了 AF 以允许使用 this customization 生成 ApiController。
由于进一步的定制需求,我想创建一个 SpecimenBuilder
来创建任何类型的 ApiController 并使用简单的
fixture.Create<DummyController>();
我试过这个测试 (NUnit 3) :
[TestFixture]
public class ApiControllerSpecimenBuilderTests
{
[Test]
public void ShouldCreateAControllerUsingSpecimenBuilder()
{
var fixture = new Fixture()
.Customize(new AutoMoqCustomization())
.Customize(new ApiControllerCustomization());
fixture.Customizations.Add(new ApiControllerSpecimenBuilder());
var ctl = fixture.Create<DummyController>();
}
}
public class ApiControllerCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Inject(new UriScheme("http"));
fixture.Customize<HttpConfiguration>(c => c
.OmitAutoProperties());
fixture.Customize<HttpRequestMessage>(c => c
.Do(x =>
x.Properties.Add(
HttpPropertyKeys.HttpConfigurationKey,
fixture.Create<HttpConfiguration>())));
fixture.Customize<HttpRequestContext>(c => c
.Without(x => x.ClientCertificate));
}
}
public class ApiControllerSpecimenBuilder : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
var t = request as Type;
if (t == null || !typeof(ApiController).IsAssignableFrom(t))
{
return new NoSpecimen();
}
var controller = context.Resolve(t) as ApiController;
// ...
return controller;
}
}
public class DummyController : ApiController
{
}
失败并出现以下错误:
Ploeh.AutoFixture.ObjectCreationException : AutoFixture was unable to create an instance of type System.RuntimeType because the traversed object graph contains a circular reference. [...]
Path: Foo.Common.Tests.AutoFixture.SpecimenBuilders.DummyController --> Foo.Common.Tests.AutoFixture.SpecimenBuilders.DummyController
为什么 DummyController 有对其自身类型的引用?
此外,如果我用 DummyController 的空自定义更改测试,它会通过:
[Test]
public void ShouldCreateAControllerUsingSpecimenBuilder()
{
var fixture = new Fixture()
.Customize(new AutoMoqCustomization())
.Customize(new ApiControllerCustomization())
.Customize(new DummyControllerCustomization()); // new customization
fixture.Customizations.Add(new ApiControllerSpecimenBuilder());
var ctl = fixture.Create<DummyController>();
}
public class DummyControllerCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<DummyController>(c => c);
}
}
在这种情况下,SpecimenBuilder 似乎不再受 DummyController 类型的影响。这个空的定制做了什么使测试通过?它会覆盖样本生成器吗?但是为什么它不抛出同样的异常,因为我没有告诉他省略任何东西(无论如何,我不知道要省略什么...)?
我想我可以使用 OmitOnRecursionBehavior
,但我想保留默认行为以避免在所有其他情况下递归,而且我更愿意了解正在发生的事情(或者如果我这样做了smth 真的很愚蠢)。
只需删除 ApiControllerSpecimenBuilder
:
[TestFixture]
public class ApiControllerSpecimenBuilderTests
{
[Test]
public void ShouldCreateAControllerUsingSpecimenBuilder()
{
var fixture = new Fixture()
.Customize(new AutoMoqCustomization())
.Customize(new ApiControllerCustomization());
//fixture.Customizations.Add(new ApiControllerSpecimenBuilder());
var ctl = fixture.Create<DummyController>();
}
}
以上版本的测试通过(在我的机器上)。
问题是ApiControllerSpecimenBuilder
如果通过初始保护子句就进入无限递归:
var controller = context.Resolve(t) as ApiController;
调用context.Resolve(t)
进入新对象创建'session'。 AutoFixture 询问其树中的每个 ISpecimenBuilder
是否可以处理 t
的请求。当它到达 ApiControllerSpecimenBuilder
时,它会再次调用 context.Resolve(t)
进行响应,如此循环往复。
您不需要自己做任何这些工作,因为 AutoFixture 已经完全能够为您创建 ApiController
个实例(只要 ApiControllerCustomization
到位)。
如果我正确理解了整个用例,但是,实际要求是您希望在创建 AutoFixture 后对 ApiController
实例进行某种 post 处理适合你的对象。
这种情况的一般解决方案是使用 Postprocessor
或 Postprocessor<T>
,但有时可能需要一些时间才能正确处理。通常,有更简单的方法可以实现您想要做的事情。
如果您需要这方面的帮助,请提出另一个问题。下次你不需要悬赏,因为我通常会监控 autofixture 标签。这个问题不知何故没有引起我的注意。抱歉!