2012-10-17 47 views
6

我有一個結構例如爲:創建具有autofixture一個struct拋出沒有公共構造錯誤

public struct Foo 
{ 
    public int Bar; 
    public string Baz; 
} 

,並想在使用autofixture我的單元測試來創建它。我嘗試使用以下內容:

IFixture fixture = new Fixture(); 
var f = fixture.CreateAnonymous<Foo>(); 

但是這會引發AutoFixture was unable to create an instance錯誤。是否有可能自動創建一個結構與自動混合?這怎麼能做到?請注意,我正在處理遺留代碼,因此需要處理結構。 :)

編輯:

改變

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

IFixture fixture = new Fixture(); 

由於這是不相關的問題。

+0

如果您取消AutoMoq自定義,它是否有所不同? –

+0

它沒有任何區別。 – Rok

+1

酷 - 無法解決問題,@Peter Porfy可以消除他的猜測... –

回答

8

這本質上是C#編譯器如何處理值類型的一種人造物。雖然the documentation seems to indicate otherwise,從反射的角度來看,Foo結構沒有公共構造函數。

E.g.如果您執行此代碼:

var ctors = typeof(Foo).GetConstructors(); 

結果是一個空數組。

然而,這個代碼編譯:

var f = new Foo(); 

,所以你可能會說,AutoFixture應該能夠創建富的一個實例。

然而,最終,mutable structs are evil,應該不惜一切代價避免。更好的選擇是改變美孚實現這樣:

public struct Foo 
{ 
    public Foo(int bar, string baz) 
    { 
     this.Bar = bar; 
     this.Baz = baz; 
    } 

    public readonly int Bar; 
    public readonly string Baz; 
} 

如果你這樣做,你不僅現在有一個(更)正確的值類型,但AutoFixture也能沒有進一步修改,以創建一個實例。

因此,這是GOOS範例的一個很好的例子,您應該傾聽您的測試。如果它們存在摩擦,它可能是關於您的生產代碼的反饋。在這種情況下,這正是反饋意見,因爲值類型實現是有缺陷的,所以您即將在腳中自拍。

P.S.即使你像上面概述的那樣'修復'Foo結構,將它變成一個結構而不是一個類又有什麼意義呢?它仍然包含一個字符串(引用類型)字段,所以即使結構本身要在棧中生存,字符串字段仍然會指向堆中的數據。


我已經添加了this issue作爲AutoFixture的一個可能的新功能。

+0

謝謝您的詳盡答案!我將添加構造函數結構,因爲這不會影響遺留代碼,但由於相同的原因,我不能使它們不可變。 至於結構,它們被用作DTO的遺留代碼。因爲在我看來,類更適合工作,所以我試圖重構一部分代碼來使用類。但是由於結構仍然會被代碼的其他部分使用,所以我需要測試它們和替換類之間的轉換。我希望我用這個用例。 :)也請回復,如果功能得到實施! – Rok

1

從這個blog post得到暗示,我創建了一個實現的ISpecimenBuilder

class FooBuilder : ISpecimenBuilder 
{ 
    public object Create(object request, ISpecimenContext context) 
    { 
    var sr = request as SeededRequest; 
    if (sr == null) 
    { 
     return new NoSpecimen(request); 
    } 
    if (sr.Request != typeof(Foo)) 
    { 
     return new NoSpecimen(request); 
    } 

    var foo = new Foo(); 
    foo.Bar = context.CreateAnonymous<int>(); 
    foo.Baz = context.CreateAnonymous<string>(); 
    return foo; 
    } 
} 

,並添加了類作爲定製

fixture.Customizations.Add(new FooBuilder()); 

導致調用CreateAnonymous<Foo>工作一類。

如果有更多開箱即用的解決方案,請發佈,我會接受它作爲答案。

+0

+1你可能能夠使用'AutoPropertiesCommand如[本討論](http://autofixture.codeplex.com/discussions/222358)所示,以自動完成任務 - –

+0

@anonympous Downvoter。任何你願意分享的理由?在沒有更好的解決方案的情況下,這是一個工作(我敢說它是最常用的方式,因爲它以正確的方式掛住了管道)解決方法(尤其是其他的泛化) –

相關問題