2017-09-27 46 views
3

我想使用AutoFixture(3.50.6)生成一些ApiController(WebAPI 2)的子類。爲什麼使用樣本生成器時,我會得到循環引用DummyApiController - > DummyApiController?

我自定義AF以允許使用this customization生成ApiControllers。

由於進一步定製需求,我想創建一個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.Object CreationException:AutoFixture無法 創建一個System.RuntimeType類型的實例,因爲遍歷的 對象圖包含循環引用。 [...]

路徑: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,但我想保持默認行爲以避免所有其他情況下的遞歸,另外我寧願瞭解發生了什麼(或者如果我確實做得很傻)。

+0

完美的問題:我有一次嘗試複製。好工作:) –

回答

1

只是刪除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)的呼叫進入一個新對象的創建「會話」。 AutoFixture會在其樹中詢問每個ISpecimenBuilder他們是否可以處理t的請求。當它達到ApiControllerSpecimenBuilder時,它通過再次呼叫context.Resolve(t)作出響應,如此等等。

由於AutoFixture已經完全能夠爲您創建ApiController實例(只要ApiControllerCustomization已準備就緒),您無需自己完成任何工作。

但是,如果我正確理解整體用例,實際要求是您希望在AutoFixture爲您創建對象之後對ApiController實例進行某種後處理。

這種情況下的一般解決方案是使用PostprocessorPostprocessor<T>,但有時候可能會涉及到一些問題。通常,有更簡單的方法來實現你想要做的事情。

如果您需要幫助,請提出另一個問題。下次你不需要付出賞金,因爲我通常會監測自動混合標記。這個問題不知怎麼逃過了我的注意。對於那個很抱歉!

+0

感謝您的回答(不要擔心獎金)。至少我現在更瞭解標本製造者如何工作。如果我遇到更多麻煩,我會通知您:) –

+0

但有一個問題仍然存在:爲什麼在定製化之後跳過了標本生成器? –

+0

@ X.L.Ant因爲你在AutoFixture中做的所有事情都被打包成一個'ICustomization',[Customizations的順序很重要](http://blog.ploeh.dk/2012/07/31/TheorderofAutoFixtureCustomizationsmatter)。因此,在您的特定示例中,第二個定製覆蓋第一個定製,並且由於它沒有做任何事情,所以相當於我完全刪除ApiControllerSpecimenBuilder的解決方案。 –

相關問題