2012-04-25 65 views
2

類AutoFixture.CreateAnonymous <>()我已經做了類似下面的如何在內部構造函數

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

public class Bar 
{ 
    internal Bar(string id) 
    {} 
} 

public static class Bars 
{ 
    public static class TypeOne 
    { 
      public static readonly SimpleBar = new Bar("id-for-type1-simple-bar"); 
    } 
} 

現在,我在單元測試組件添加了InternalsVisibleTo我要能訪問內部酒吧構造函數,然後我做:

var fixture = new Fixture(); 
fixture.Register(() => new Bar(fixture.CreateAnonymous<string>())); 
var foo = fixture.CreateAnonymous<Foo>(); 

問:
是「正確」的方式來利用AutoFixture或者是有一個更好的?

+3

「正確」的方法是隻測試被測系統的公共API。因此,InternalsVisibleTo充其量只是治療症狀而不是疾病。你不能讓構造函數公開嗎? – 2012-04-25 16:56:25

+0

@MarkSeemann:我可以,但'Bar'實例的所有可能值都列在'static class Bars'中 - 因此不需要創建其他實例... – Nils 2012-04-25 18:07:40

回答

2

難道你不能只是做這樣的事情呢?

fixture.Inject(Bars.TypeOne.SimpleBar); 

這是全部公開的。無需InternalsVisibleTo,我想......

+0

+1根據您的評論,最明智的做法是唯一允許的值由「酒吧」已知# – 2012-04-26 07:33:37

2

此代碼的工作,因爲你已經有一個公共靜態類引用吧,這個工作沒有設置InternalsVisibleTo屬性

 var fixture = new Fixture().Customize(new AutoMoqCustomization()); 

     fixture.Inject(Bars.TypeOne.SimpleBar); 

     var sut = fixture.CreateAnonymous<Foo>(); 

     sut.Should().NotBeNull(); 
     sut.Bar.Should().NotBeNull(); 
     sut.Bar.Should().Be(Bars.TypeOne.SimpleBar); 
2

永遠不要往下走的路InternalsVisibleTo - 不要讓我開始列表,但它始於系統的每個部分,包括所有強名單的測試助手。

如果你絕對不能這麼想 - 大多數情況下你最好把內部部件放在內部,你不會考慮把你的公共API放到命名空間中,這樣它們就不會混淆任何東西 - 例如Xunit.Sdk和我爲僱主使用的各種子命名空間),然後正確的方式來管理這些暴露的東西。僅供測試使用的是For Tests Only的概念。注意這個名字的原因在於它被正確地稱爲the xUnit Test Patterns book中的反模式。


現在回答你的問題......

  1. 考慮隱藏的東西,用戶一般不應該需要一個單獨的命名空間
  2. 不要使用InternalsVisibleTo
  3. 不使用只測試代碼

公開一個只在內部暴露的工廠(可能是?)構建軟件的(但最好你有它在另一個命名空間無條件):

#if INCLUDE_FOR_TEST_ONLY 
public static class BarsForTestOnly 
{ 
    public static Bar Create(string id) 
    { 
     return new Bar(id); 
    } 
} 
#endif 

而且使用這樣的:

#if INCLUDE_FOR_TEST_ONLY 
public class Facts 
{ 

[Fact] 
public void Fact() 
{ 
    Fixture fixture = new Fixture(); 
    fixture.Register((string name) => BarsForTestOnly.Create(name)); 
    var anonymousBar = fixture.CreateAnonymous<Bar>(); 
} 

[Fact] 
public void FactSyntax2() // Just a variant of Fact above 
{ 
    Fixture fixture = new Fixture(); 
    fixture.Register<string, Bar>(BarsForTestOnly.Create); 
    var anonymousBar = fixture.CreateAnonymous<Bar>(); 
} 

[Fact] 
public void UsingFromFactory() 
{ 
    Fixture fixture = new Fixture(); 
    fixture.Customize<Bar>( x=> x.FromFactory<string>(BarsForTestOnly.Create)); 
    var anonymousBar = fixture.CreateAnonymous<Bar>(); 
} 
#endif 

或者,使你有Just Work,你可以這樣做:

[Fact] 
public void UsingCtor() 
{ 
    Fixture fixture = new Fixture(); 
    fixture.Register((string name)=> new Bar(name)); 
    var anonymousBar = fixture.CreateAnonymous<Bar>(); 
} 
+1

+1在命名空間中「隱藏」事物的另一種替代方法是將接口用作一種訪問修飾符本身:http://blog.ploeh.dk/2011/02/28/InterfacesAreAccessModifiers.aspx – 2012-04-26 10:57:50

+0

@Mark Seemann:已閱讀並重視該文章中的見解,但這裏並沒有想到它。定義一個在這個空間中考慮的技術。 (儘管顯然在這個特定的情況下,它(僅在一個明確實現的接口上的方法)只有在你已經擁有了一個對象的實例後才變得有價值,這是OP後面的雞)。 – 2012-04-26 12:16:05