Die folgenden Tests sind in AutoFixture 3.51.0
erfolgreich, schlagen jedoch in 4.0.0-rc1
fehl:
(sogar im neuesten Commit im Master: c856cd6
)
``` c#
[Tatsache]
public void ShouldApplyCustomizationsFromBaseClass()
{
var Fixture = new Fixture();
Befestigung.Anpassen
var res = Fixture.Create
Assert.Equal(0, res.Id);
}
[Tatsache]
public void ShouldApplyCustomizationsFromInterface()
{
var Fixture = new Fixture();
Befestigung.Anpassen
var res = Fixture.Create
Assert.Equal(0, res.Id);
}
öffentliche Schnittstelle IInterface
{
int-Id { erhalten; einstellen; }
}
öffentliche Klasse BaseClass
{
öffentliche int-Id { get; einstellen; }
}
öffentliche Klasse ImplClass : BaseClass, IInterface
{
}
```
Danke, dass du die Frage gestellt hast. Nun, dies ist die gewünschte Änderung und wurde absichtlich vorgenommen.
Zuvor hatten wir ein Problem, bei dem sich die Anpassung eines Untertyps auf einen anderen Untertyp auswirken konnte. Zum Beispiel:
```c#
Klasse Basis { öffentlicher String Common { get; einstellen; } }
Klasse Child1: Basis { }
Klasse Child2: Basis { }
[Tatsache]
public void ProvideCustomizationAreNotAffected()
{
var Fixture = new Fixture();
Befestigung.Anpassen
var result = fixture.Create<Child2>();
Assert.NotNull(result.Common);
}
In the v3 this test failed, causing a lot of confusion to people. As you might imagine, the scenarios were more complicated and it was very non-obvious why the particular members are not initialized.
For instance, the following code will not work, which again proves that API is not designed for that.
```c#
fixture.Customize<Base>(c => c.With(x => x.Common, "foo"));
Um dieses Problem zu beheben, haben wir den Ansatz geändert , sodass die Anpassung eines Typs jetzt keine Auswirkungen auf andere Typen hat, selbst wenn sie zur gleichen Vererbungslinie gehören. Wie Sie vielleicht in dieser PR sehen können, wurden eine Reihe von Usability-Problemen behoben und mehr Klarheit geschaffen (während die Änderung tatsächlich kaputt geht).
Wenn Sie Basis-/Schnittstelleneigenschaften dennoch weglassen möchten, können Sie das folgende Snippet verwenden:
```c#
private Klasse SamePropertySpecification : IRequestSpecification
{
privater schreibgeschützter Typ _declaringType;
private schreibgeschützte Zeichenfolge _name;
public SamePropertySpecification(Type declaringType, string name)
{
_declaringType = declaringType;
_name = name;
}
public bool IsSatisfiedBy(object request)
{
if (request is PropertyInfo pi)
{
return pi.DeclaringType == this._declaringType &&
pi.Name.Equals(this._name, StringComparison.Ordinal);
}
return false;
}
}
[Tatsache]
public void TestBasePropertyOmitting()
{
var Fixture = new Fixture();
fixture.Customizations.Add(new Omitter(new SamePropertySpecification(typeof(Base), nameof(Base.Common))));
var result = fixture.Create<Child1>();
Assert.Null(result.Common);
}
```
Wenn Sie diese Funktion häufig benötigen, können Sie Ihre eigene Erweiterungsmethode für fixture
erstellen. Ich würde jedoch dafür stimmen, ein solches Feature nicht out-of-the-box zu haben, da es sehr verwirrend aussieht.
Okay, gut zu wissen, dass es Absicht war. Ich stimme definitiv zu, dass es verwirrend war, aber wenn es explizit angewendet werden kann, ist es ein nettes Feature. Werde dein Snippet ausprobieren (und wahrscheinlich die Erweiterungsmethode machen).
Übrigens: Wollen Sie das in die Breaking-Change-Liste aufnehmen? Könnte verhindern, dass dieselbe Frage erneut gestellt wird.
Es gibt keine Möglichkeit, das alte Verhalten für eine Anpassung aller Anpassungen zu aktivieren, oder?
Möchten Sie dies der Liste der Breaking Changes hinzufügen?
Nun, es wird im Abschnitt " Fehlerbehebungen " erwähnt. Dies ist in der Tat keine Breaking Change, da das vorherige Verhalten nie als "Feature" angegeben wurde. Das war eher ein ungewollter Nebeneffekt und wurde endgültig beseitigt 😉
Es gibt keine Möglichkeit, das alte Verhalten für eine Anpassung aller Anpassungen zu aktivieren, oder?
Nein, das gibt es meiner Meinung nach nicht, da ich den Ansatz komplett überarbeitet habe.
Bitte testen Sie das Snippet und wenn es funktioniert, können Sie das Problem gerne schließen. Oder lass es mich wissen, wenn du weitere Fragen hast 😃
Ich habe es so optimiert, dass es auch für Schnittstellen funktioniert und eine Erweiterungsmethode erstellt, damit es in "Fixture.Customize" verwendet werden kann
@nphmuller Entschuldigung, dass ich deinen
Überhaupt keine Schuld. Verstehe deine Argumentation perfekt und stimme sogar zu. Schade für mich
Könnte später in das Problem eintauchen, um zu sehen, ob es einen saubereren Weg gibt. Im Moment ist es in Ordnung.
Nur aus Neugier - was ist Ihr wirklicher Anwendungsfall dafür? Weil ich nie einen Bedarf an einer solchen Funktionalität gedeckt habe. Wenn ich einen Test schreibe, muss ich normalerweise nur einen bestimmten Typ anpassen, anstatt den Basis- oder Schnittstellentyp zu konfigurieren. Schreiben Sie eine Art globale Anpassung?
In diesem Fall verwenden wir AutoFixture als Testdatengenerator für Entity Framework-Integrationstests.
Wir haben einige Basistypen oder Schnittstellen, die unsere Entitäten verwenden, die gemeinsame Eigenschaften enthalten. ID, Tenant-ID (und Navigationseigenschaft), solche Sachen.
Eine dieser Eigenschaften ist beispielsweise, welcher Benutzer das Objekt erstellt hat. Diese Eigenschaft ist für die meisten Tests nicht so interessant, und wenn sie generiert würde, würde sie einen riesigen Graphen erzeugen (die User-Klasse hat auch viele Navigationseigenschaften), der generiert und in die Datenbank eingefügt werden müsste. Dies würde den Test verlangsamen oder sogar auf DB-Ebene fehlschlagen, weil das Objekt nicht auf diese Weise eingefügt werden sollte.
Daher ist es einfacher, diese Eigenschaften einfach auszuschließen und bei Bedarf zu aktivieren. Auf Basisklassenebene, weil sonst für jeden Entitätstyp die gleiche Auslassungsregel geschrieben werden müsste.
@nphmuller Danke für die Klarstellung, jetzt ist es klar 😉 Ja, das Szenario sieht so aus, als ob es Sinn macht, aber ich muss zugeben, es sieht so aus, als ob man es ziemlich selten braucht.