2012-10-17 5 views
6

Ich habe eine Struktur z.B .:eine Struktur mit autofixture Erstellen werfen keine öffentlichen Konstruktor Fehler

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

und möchte es in meinen Unit-Tests autofixture mit erstellen. Ich habe folgendes versucht:

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

Aber das wirft einen AutoFixture was unable to create an instance Fehler. Ist es möglich, eine Struktur mit Autofixierung automatisch zu erstellen? Wie könnte das gemacht werden? Bitte beachten Sie, dass ich an Legacy-Code arbeite und daher mit Strukturen arbeiten muss. :)

EDIT:

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

Um

IFixture fixture = new Fixture(); 

Da es nicht relevant für die Frage war.

+0

Wenn Sie die AutoMoq-Anpassung entfernen, macht es einen Unterschied oder nicht? –

+0

Es macht keinen Unterschied. – Rok

+1

Cool - nehmen Sie es in Frage und @Peter Porphy kann seine Spekulation entfernen ... –

Antwort

8

Dies ist im Wesentlichen ein Artefakt, wie der C# -Compiler Werttypen behandelt. Während the documentation seems to indicate otherwise, aus der Perspektive von Reflection, hat die Foo-Struktur keine öffentlichen Konstruktoren.

z. Wenn Sie diesen Code ausführen:

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

Das Ergebnis ist ein leeres Array.

jedoch dieser Code kompiliert:

var f = new Foo(); 

so könnte man argumentieren, dass AutoFixture Lage sein sollte, eine Instanz von Foo zu erstellen.

Allerdings, am Ende, mutable structs are evil und sollte um jeden Preis vermieden werden. Eine bessere Option ist, die Foo-Implementierung, dies zu ändern:

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

    public readonly int Bar; 
    public readonly string Baz; 
} 

Wenn Sie dies tun, nicht nur haben Sie jetzt einen (mehr) korrekt Werttyp, aber AutoFixture ist auch in der Lage, eine Instanz ohne weitere Modifikation zu erstellen .

So ist dies ein ziemlich gutes Beispiel für die GOOS Paradigma, die Sie sollten hören Sie Ihre Tests. Wenn sie Reibung zeigen, könnte dies eine Rückmeldung über Ihren Produktionscode sein. In diesem Fall ist dies genau das Feedback, das Sie selbst in den Fuß schießen, weil die Implementierung des Werttyps fehlerhaft ist.

P.S. Selbst wenn Sie die Foo-Struktur wie oben beschrieben "fixieren", was bringt es, sie zu einer Struktur anstelle einer Klasse zu machen? Es enthält immer noch ein Feld für Zeichenketten (Referenztypen). Obwohl die Struktur selbst auf dem Stapel leben wird, wird das Zeichenfolgenfeld immer noch auf Daten im Heap zeigen.


Ich habe this issue als mögliches neues Feature für AutoFixture hinzugefügt.

+0

Vielen Dank für die erschöpfende Antwort! Ich werde Konstruktoren hinzufügen Strukturen, da dies den Legacy - Code nicht beeinflusst, aber aus dem gleichen Grund kann ich sie nicht unveränderlich machen Wie für die Strukturen werden sie als DTOs von der Legacy-Code. Da meiner Meinung nach Klassen besser für den Job geeignet sind, versuche ich einen Teil des Codes zu refaktorisieren, um stattdessen Klassen zu verwenden. Aber da Strukturen immer noch von anderen Teilen des Codes verwendet werden, muss ich Konvertierungen zwischen ihnen und Ersatzklassen testen. Ich hoffe, ich mache damit einen Anwendungsfall. :) Bitte poste auch zurück, wenn Feature get implementiert wurde! – Rok

1

ein Stichwort aus diesem blog post nehmen, habe ich eine Klasse, die die 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; 
    } 
} 

umgesetzt und hinzugefügt, um die Klasse als Anpassung zu arbeiten

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

den Anruf zu CreateAnonymous<Foo> verursacht.

Wenn es eine Out-of-the-Box-Lösung gibt, bitte posten Sie es und ich werde es als Antwort akzeptieren.

+0

+1 Du könntest 'AutoPropertiesCommand verwenden 'wie in [dieser Diskussion] (http://autofixture.codeplex.com/discussions/222358) gezeigt, um die Zuordnung zu automatisieren - –

+0

@anonymous Downvoter. Gibt es irgendwelche Gründe, die Sie teilen möchten? In Ermangelung einer besseren Lösung, Dies ist eine Arbeit (und ich wage es zu sagen, dass es die Sprache in der richtigen Weise hakt) Workaround (esp mit der anderen Verallgemeinerung) –

Verwandte Themen