Autofixture: Das Erstellen einer benutzerdefinierten Instanz schlägt bei Zirkelverweisen fehl

Erstellt am 13. Jan. 2018  ·  5Kommentare  ·  Quelle: AutoFixture/AutoFixture

    [TestFixture]
    public class TestAutoFixture4
    {
        [Test]
        [AutoMoqData]
        public void CreatingAnDummyObjectShouldNotThrow(IFixture fixture)
        {
            fixture.Invoking(x => x.Create<DummyObject>()).ShouldNotThrow();
        }

        [Test]
        [AutoMoqData]
        public void BuildingAnDummyObjectShouldNotThrow(IFixture fixture)
        {
            fixture.Invoking(x => x.Build<DummyObject>().Create()).ShouldNotThrow();
        }
    }

    public class DummyObject
    {
        public Guid Id { get; set; }
        public DummyObject CircularRef { get; set; }
    }

    public class AutoMoqDataAttribute : AutoDataAttribute
    {
        public AutoMoqDataAttribute()
            : base(new Fixture()
                 .Customize(
                    new DummyCustomization()
                ))
        { }
    }

    public class DummyCustomization : ICustomization
    {
        public void Customize(IFixture fixture)
        {
            fixture.Customize<DummyObject>(c =>
                c.Without(x => x.CircularRef)
            );
        }
    }

Gerade AutoFixture von 3.50.6 auf 4.0.0 aktualisiert.

Der obige Code funktioniert perfekt auf 3.50.6, aber nur der erste Test (mit Fixture.Create) besteht mit 4.0.0 (.NET 4.6.2, NUnit3.7.1, FluentAssertions 4.19.4).

Der Test mit Fixture.Build schlägt fehl, selbst wenn die eingefügte Anpassung angibt, die Zirkelreferenz nicht aufzulösen.

Habe ich etwas im Changelog übersehen oder ist es ein Bug?

Danke im Voraus :)

question

Hilfreichster Kommentar

Glauben Sie, dass der Omitter-Ansatz das Problem lösen kann? Ich kannte diese Klasse noch nicht und werde sie auf jeden Fall ausprobieren.

Wenn Sie Ihre Anpassung wie folgt umschreiben, beginnen alle Tests zu bestehen:

c# public class DummyCustomization : ICustomization { public void Customize(IFixture fixture) { // Don't populate the DummyObject.CircularRef property. fixture.Customizations.Add( new Omitter( new EqualRequestSpecification( typeof(DummyObject).GetProperty(nameof(DummyObject.CircularRef))))); } }

Daher, ja, es sollte Ihr Problem beheben 😉 Auch dieser Ansatz sieht nicht zu umständlich aus, sollte also akzeptabel sein.

Bitte lassen Sie mich wissen, wenn Sie weitere Fragen zu Ihrer Frage haben.

Alle 5 Kommentare

@Dev-I-Ant Danke, dass du das Problem hier gepostet hast und für eine so detaillierte Beschreibung

Nun, dieses Verhalten ist das Ergebnis der in #781 vorgenommenen Änderungen. Ich habe das Problem behoben, bei dem eine Anpassung andere Anpassungen beeinflussen konnte. Das passiert auch, wenn Sie zwei nachfolgende Anpassungen für denselben Typ haben – die vorherige wird vollständig ignoriert.

Wenn Sie die API Build<T>() , erstellen Sie tatsächlich eine temporäre Anpassung für den Typ DummyObject . Das bedeutet, dass alle vorherigen Anpassungen (die über die Customize<DummyObject>() API angewendet wurden) ignoriert werden und nicht teilnehmen. Aus diesem Grund sehen Sie erneut einen Fehler bezüglich der zirkulären Abhängigkeit.

Diese Art der Isolierung ist erforderlich, da sonst sehr seltsame Probleme auftreten können (siehe die oben genannten Probleme in der oben genannten PR). Daher würde ich der Einfachheit halber sagen, dass das beobachtete Verhalten kein Fehler ist, sondern eine Besonderheit unseres aktuellen Designs.


Um das von Ihnen beobachtete Problem zu mildern, sehe ich im Wesentlichen zwei Möglichkeiten.

Problemumgehung 1: Fügen Sie Omitter für die Eigenschaft hinzu

Wir hatten bereits eine ähnliche Frage, sodass Sie den hier vorgeschlagenen Ansatz wiederverwenden oder an Ihre Bedürfnisse anpassen können. Wenn dies ein häufiges Szenario in Ihrem Projekt ist, können Sie natürlich eine Erweiterungsmethode erstellen, um die Aufgabe einfacher zu lösen.

Problemumgehung 2: Verwenden Sie stattdessen die Create<T>() API

In Ihrem Beispiel müssen Sie die API Build<> . Natürlich kann es sein, dass Sie ein vereinfachtes Beispiel bereitgestellt haben und diese API tatsächlich benötigen. Ich habe mich jedoch entschlossen, Ihnen diese Option nur für den Fall zur Verfügung zu stellen 😃

Lassen Sie mich wissen, ob meine Antwort dazu beigetragen hat, Licht in dieses Thema zu bringen 😉

@zvirja Danke für deine Einblicke, das macht die Sache klarer.

Ich habe schon viel darüber gelesen, dass das Stapeln von Anpassungen auf demselben Typ nicht möglich ist (auch wenn es frustrierend ist), und diese Änderung wird mir sicherlich einige Probleme bereiten, aber ich verstehe, warum Sie etwas ändern mussten.

Mein Anwendungsfall ist das Testen einer Anwendung mit einem großen Graphen von Objekten mit vielen Zirkelbezügen; das typische (Anti-?)Muster, bei dem ein Elternteil eine Liste von Kindern hält, die wiederum auf ihre Eltern verweisen.

Ich würde gerne das Modell ändern, aber es ist zumindest im Moment nicht möglich.

Das einfache Erstellen von Objekten mit Fixture.Create ist also keine Option und wir erstellen sie normalerweise mit dem Aufrufen von OmitAllProperties gleich danach, was die Leistung von AF einschränkt.

Also habe ich einige Anpassungen erstellt, die das für mich erledigt haben, indem ich die Zirkelverweise weggelassen habe (dann mussten die Entwickler nur ihre Objekte erstellen, ohne sich darum kümmern zu müssen, ob es Zirkelverweise gab oder nicht, und sie mit With weiter anpassen zu können, Ohne usw.). Aber diese Veränderung bricht all dies irgendwie.
Glauben Sie, dass der Omitter-Ansatz das Problem lösen kann? Ich kannte diese Klasse noch nicht und werde sie auf jeden Fall ausprobieren.

Nochmals vielen Dank, und lassen Sie es mich bitte wissen, wenn Sie meinen, dass Sie etwas zu meiner Reflexion hinzufügen können.

Glauben Sie, dass der Omitter-Ansatz das Problem lösen kann? Ich kannte diese Klasse noch nicht und werde sie auf jeden Fall ausprobieren.

Wenn Sie Ihre Anpassung wie folgt umschreiben, beginnen alle Tests zu bestehen:

c# public class DummyCustomization : ICustomization { public void Customize(IFixture fixture) { // Don't populate the DummyObject.CircularRef property. fixture.Customizations.Add( new Omitter( new EqualRequestSpecification( typeof(DummyObject).GetProperty(nameof(DummyObject.CircularRef))))); } }

Daher, ja, es sollte Ihr Problem beheben 😉 Auch dieser Ansatz sieht nicht zu umständlich aus, sollte also akzeptabel sein.

Bitte lassen Sie mich wissen, wenn Sie weitere Fragen zu Ihrer Frage haben.

Dies funktioniert einwandfrei. Danke vielmals! Ich denke, du kannst das dann schließen :)

@Dev-I-Ant Super, danke für das Feedback! :)

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

malylemire1 picture malylemire1  ·  7Kommentare

ploeh picture ploeh  ·  3Kommentare

JoshKeegan picture JoshKeegan  ·  6Kommentare

zvirja picture zvirja  ·  3Kommentare

tiesmaster picture tiesmaster  ·  7Kommentare