2012-04-05 11 views
6

Ich bin dabei, das Erstellungszeitverhalten von AutoFixture so anzupassen, dass ich einige abhängige Objekte einrichten kann, nachdem die Eigenschaften des Fixtures generiert und zugewiesen wurden.Kann AutoFixture einen Delegaten zum Zeitpunkt der Objekterstellung ausführen?

Zum Beispiel nehme ich eine Methode, die eine besonders anfertigt User weil seine IsDeleted Eigenschaft hat immer für einen bestimmten Satz von Tests falsch sein:

public class User 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public bool IsDeleted { get; set; } 
} 

public static ObjectBuilder<User> BuildUser(this Fixture f) 
{ 
    return f.Build<User>().With(u => u.IsDeleted, false); 
} 

(Ich gebe ein ObjectBuilder zum Test zurück, so dass es kann das Gerät bei Bedarf weiter anpassen.)

Was ich tun möchte ist, diesen Benutzer automatisch mit einer anonymen Sammlung von seiner Id bei der Erstellung verknüpfen, aber ich kann dies nicht tun, da Id nicht hat wurde durch die Zeit erzeugt, die ich übergebe der Rückgabewert zurück zum eigentlichen Komponententest. Hier ist die Art von Sache, die ich versuche zu tun:

public static ObjectBuilder<User> BuildUserIn(this Fixture f, UserCollection uc) 
{ 
    return f.Build<User>() 
      .With(u => u.IsDeleted, false); 
      .AfterCreation(u => 
      { 
       var relation = f.Build<UserCollectionMembership>() 
           .With(ucm => ucm.UserCollectionId, uc.Id) 
           .With(ucm => ucm.UserId, u.Id) 
           .CreateAnonymous(); 
       Repository.Install(relation); 
      } 
} 

Ist so etwas möglich? Oder gibt es vielleicht einen besseren Weg, um mein Ziel zu erreichen, ein anonymer Objektgraph zu erstellen?

+0

Möchten Sie eine bestimmte Instanz für den Benutzertyp haben und den Id-Eigenschaftswert woanders wiederverwenden? –

+2

Hilft das? http://StackOverflow.com/questions/5398258/customizing-autofixture-builder-with-seeded-property/5398653#5398653 –

+0

@MarkSeemann: 'Do()' kann scheinbar ausgeführt werden, bevor das Objekt vollständig ausgefüllt ist, so dass dies nicht ' t arbeiten. Ich kann (und tue) das Beispiel-Lambda manuell ausführen oder mache meine Objekt-Anpassung nach der Erstellung, aber ich würde eine Alternative ähnlich der oben genannten lieben! – ladenedge

Antwort

6

Für die Build Methode ist dies nicht möglich, und wahrscheinlich wird es nie sein, weil es viel bessere Optionen gibt.

Zunächst sollte es nie notwendig sein, statische Hilfsmethoden um die Build Methode zu schreiben. Die Build Methode ist für wirklich einmalige Initialisierungen, bei denen man Eigenschafts- oder Feldwerte vor der Tatsache definieren muss.

I.e. stellen Sie sich eine Klasse wie folgt:

public class MyClass 
{ 
    private string txt; 

    public string SomeWeirdText 
    { 
     get { return this.txt; } 
     set 
     { 
      if (value != "bar") 
       throw new ArgumentException(); 
      this.txt = value; 
     } 
    } 
} 

In diesem (erfundenen) beispielsweise ein gerade fixture.CreateAnonymous<MyClass> geht zu werfen, weil es versuchen, wird etwas anderes als „bar“ auf die Eigenschaft zuweisen.

In einem einmaligen Szenario kann die Methode Build verwendet werden, um dieses Problem zu umgehen. Ein Beispiel dafür ist einfach, den Wert zu setzen explizit auf „bar“:

var mc = 
    fixture.Build<MyClass>().With(x => x.SomeWeirdText, "bar").CreateAnonymous(); 

, jedoch noch einfacher wäre wegzulassen nur diese Eigenschaft:

var mc = 
    fixture.Build<MyClass>().Without(x => x.SomeWeirdText).CreateAnonymous(); 

Allerdings, wenn Sie wollen, beginnen diese immer wieder tun Es gibt bessere Möglichkeiten. AutoFixture verfügt über eine sehr ausgereifte und anpassbare Engine, um zu definieren, wie Dinge erstellt werden.

Als Anfang ein, indem Sie den Wegfall der Eigenschaft in eine Anpassung, wie dies beginnen könnte:

fixture.Customize<MyClass>(c => c.Without(x => x.SomeWeirdText)); 

Nun, wenn das Gerät erstellt eine Instanz von MyClass, es wird nur überspringt diese Eigenschaft insgesamt. Sie können immer noch einen Wert zuweisen danach:

var mc = fixture.CreateAnonymous<MyClass>(); 
my.SomeWeirdText = "bar"; 

Wenn Sie etwas wollen, anspruchsvollere, können Sie implement a custom ISpecimenBuilder. Wenn Sie nach der Erstellung der Instanz einen benutzerdefinierten Code ausführen möchten, können Sie Ihren eigenen ISpecimenBuilder mit einem Postprozessor dekorieren und einen Delegaten bereitstellen.Dass etwas könnte wie folgt aussehen:

fixture.Customizations.Add(
    new Postprocessor(yourCustomSpecimenBuilder, obj => 
     { */ do something to obj here */ })); 

(? BTW, sind Sie noch auf AutoFixture 1,0 IIRC hat es eine ObjectBuilder<T> um seitdem nicht gewesen ...)

+0

Hinzufügen eines Postprozessors möglicherweise nur das Ticket, und ich schätze den Rat zur richtigen AF-Nutzung. Vielen Dank! (In Bezug auf v1.0, ja: wir hatten einige [Probleme] (http://stackoverflow.com/questions/4650424/autofixture-2-with-istn-working-as-it-did-in-autofixture-1) [ Upgrade] (http://stackoverflow.com/questions/8595498/why-ist-autofixture-working-with-the-stringlength-data-annotation) - vielleicht wird das dritte Mal der Charme sein!) – ladenedge

3

Es gibt eine useful discussion on this topic on the AutoFixture CodePlex site.

Ich glaube, dass meine postprocessor Customization dort verlinkt Ihnen helfen sollte. Beispielverwendung:

class AutoControllerDataAttribute : AutoDataAttribute 
{ 
    public AutoControllerDataAttribute() 
     : this(new Fixture()) 
    { 
    } 

    public AutoControllerDataAttribute(IFixture fixture) 
     : base(fixture) 
    { 
     fixture.Customize(new AutoMoqCustomization()); 
     fixture.Customize(new ApplyControllerContextCustomization()); 
    } 

    class ApplyControllerContextCustomization : PostProcessWhereIsACustomization<Controller> 
    { 
     public ApplyControllerContextCustomization() 
      : base(PostProcess) 
     { 
     } 

     static void PostProcess(Controller controller) 
     { 
      controller.FakeControllerContext(); 
      // etc. - add stuff you want to happen after the instance has been created 
Verwandte Themen