2012-10-17 12 views
6

Mam struct np .:Tworzenie struct z autofixture wyrzuca żadnego błędu konstruktora publicznego

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

i chciałbyś go stworzyć w moich testów jednostkowych z wykorzystaniem autofixture. Próbowałem przy użyciu następujących:

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

Ale to zgłasza błąd AutoFixture was unable to create an instance. Czy możliwe jest automatyczne tworzenie struktury z autoformturem? Jak można to zrobić? Proszę zauważyć, że pracuję nad starszym kodem, a tym samym muszę zajmować się strukturami. :)

EDIT:

Zmieniono

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

Aby

IFixture fixture = new Fixture(); 

Ponieważ nie było istotne dla tej kwestii.

+0

Jeśli wyłączysz dostosowanie AutoMoq, czy robi różnicę, czy nie? –

+0

Nie ma to znaczenia. – Rok

+1

Fajnie - nie licz na to, a @Peter Porfy może usunąć spekulacje ... –

Odpowiedz

8

Jest to zasadniczo artefakt, w jaki sposób kompilator C# traktuje typy wartości. Podczas gdy the documentation seems to indicate otherwise, z perspektywy Reflection, struktura Foo nie ma publicznych konstruktorów.

E.g. jeśli wykonasz ten kod:

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

wynikiem jest pusta tablica.

Jednak ten kod kompiluje:

var f = new Foo(); 

więc można argumentować, że AutoFixture powinien być w stanie utworzyć wystąpienie Foo.

Jednak ostatecznie, mutable structs are evil i należy go unikać za wszelką cenę. Lepszym rozwiązaniem jest zmiana realizację Foo do tego:

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

    public readonly int Bar; 
    public readonly string Baz; 
} 

Jeśli to zrobisz, nie tylko teraz mieć (więcej) prawidłowy typ wartości, ale AutoFixture jest również w stanie stworzyć instancję bez dalszej modyfikacji .

Jest to całkiem dobry przykład paradygmatu GOOS, w którym należy posłuchać testu . Jeśli przedstawiają tarcie, może to być informacja zwrotna na temat twojego kodu produkcyjnego. W tym przypadku jest to informacja zwrotna, którą zamierzasz zastrzelić w stopie, ponieważ implementacja typu wartości jest wadliwa.

P.S. Nawet jeśli "naprawisz" strukturę Foo, jak opisano powyżej, jaki jest sens tworzenia struktury zamiast klasy? Wciąż zawiera pole typu (typy odniesienia), więc nawet jeśli sama struktura będzie żyła na stosie, pole łańcucha nadal będzie wskazywało dane w stercie.


Dodałem this issue jako nową opcję funkcji AutoFixture.

+0

Dziękuję za wyczerpującą odpowiedź! Dodam konstruktorów do structs, ponieważ nie wpłynie to na dotychczasowy kod, ale z tego samego powodu nie mogę uczynić ich niezmiennymi Jeśli chodzi o struktury, są one używane jako DTO przez starszy kod. Ponieważ moim zdaniem klasy są bardziej odpowiednie do tego zadania, próbuję zmienić część kodu, aby użyć klas. Ale ponieważ struktury będą nadal używane przez inne części kodu, muszę przetestować konwersje między nimi i klasami zastępczymi. Mam nadzieję, że zrobię z tego przypadek. :) Również proszę odeślij, jeśli funkcja jest zaimplementowana! – Rok

1

Biorąc przykład z tego blog post, stworzyłem klasę które wdrożyły 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; 
    } 
} 

i dodaje klasy jako personalizacji

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

powoduje wywołanie CreateAnonymous<Foo> do pracy.

Jeśli istnieje więcej rozwiązań z pudełka, proszę go opublikować, a ja przyjmuję to jako odpowiedź.

+0

+1 Możliwe, że będziesz mógł użyć 'AutoPropertiesCommand 'jak pokazano w [ta dyskusja] (http://autofixture.codeplex.com/discussions/222358) aby zautomatyzować zadanie - –

+0

@anonympous Downvoter.Wszelkie powody, którymi chciałbyś się podzielić? W przypadku braku lepszego rozwiązania, to działa (i śmiem twierdzić, że jest to najbardziej idiomatyczne pod względem faktu, że przechwytuje on potok w prawidłowy sposób) obejścia (w szczególności z innymi generalizacjami) –

Powiązane problemy