Autofixture: Caching für AutoMoq optional deaktivieren?

Erstellt am 20. Mai 2016  ·  14Kommentare  ·  Quelle: AutoFixture/AutoFixture

Bei Verwendung einer AutoConfiguredMoqCustomization wird der vom verwendeten Fixture zurückgegebene Wert zwischengespeichert und bei jedem Aufruf wird derselbe Wert zurückgegeben (ich bin mir nicht sicher, ob dies in MockType.ReturnsUsingContext oder anderswo geschieht, aber ich sehe einen Kommentar dazu dort in Zeile 104).

Die einzige Möglichkeit, es zu überschreiben, besteht darin, eine eingefrorene Instanz des fraglichen Mocks an die Testmethode zu übergeben und das Setup mit einer Funktion zu überschreiben, die das Gerät aufruft:

someMock.Setup(it => it.SomeMethodReturningAString()).Returns(() => fixture.Create<string>())

Gibt es eine allgemeinere / intelligentere Möglichkeit, die automatisch generierten Mocks so zu konfigurieren, dass das Gerät jedes Mal aufgerufen wird, wenn ein Wert von AutoFixture benötigt wird, außer jeden Aufruf manuell einzurichten?

enhancement good first issue

Hilfreichster Kommentar

Ich gebe zu, dass ich dachte, dass die Testdoubles so konfiguriert sind, dass sie in AutoFixture zurückrufen, um einen Rückgabewert zu erhalten. AutoFixture verfügt bereits über einen Lifetime-Management-Mechanismus (über seine Freeze-Funktionen), daher finde ich es etwas überraschend, dass AutoConfiguredMoqCustomization seinen eigenen Lifetime-Manager implementiert und damit die von AutoFixture selbst bereitgestellte Steueroberfläche überschreibt.

Alle 14 Kommentare

Die Idee hinter dem Zwischenspeichern des Ergebniswerts bestand darin, alle Methoden standardmäßig auf _pure_ zu setzen , was als bewährte Methode

Wenn das zu testende System eine reine Funktion erwartet, aber eine unreine Funktion erhält, führt der Test wahrscheinlich zu einem falsch positiven Ergebnis. Z.B

// This method will return the expected result *if* `GetInt` is pure.
int Double(IDependency dep) {
    return dep.GetInt() + dep.GetInt();
}

Assert.Equal(dep.GetInt * 2, Double(dep));

Auf der anderen Seite, wenn das zu testende System keine Reinheit annimmt, sollte es keinen Unterschied machen, ihm eine reine oder unreine Funktion zu geben.

Daher war es für mich sinnvoll, standardmäßig auf reine Funktionen zu setzen, als ich diese Funktion implementierte.

Gibt es eine allgemeinere / intelligentere Möglichkeit, die automatisch generierten Mocks so zu konfigurieren, dass das Gerät jedes Mal aufgerufen wird, wenn ein Wert von AutoFixture benötigt wird, außer jeden Aufruf manuell einzurichten?

Wenn Sie dies für die Methode _one_ tun müssen, aber über mehrere Tests hinweg, würde ich sie in ein wiederverwendbares IConfiguration legen.

Wenn Sie dies für alle Methoden über mehrere Tests hinweg tun möchten, benötigen Sie etwas mehr Arbeit:

  • Definieren Sie eine neue Implementierung von ReturnsUsingContext (IIRC, Sie können einfach die aktuelle Implementierung kopieren und Zeile 104 entfernen)
  • Definieren Sie MockVirtualMethodsCommand und ersetzen Sie den Aufruf von ReturnsUsingContext durch einen Aufruf Ihrer neuen Methode.
  • Definieren Sie AutoConfiguredMoqCustomization und ersetzen Sie die Instanzierung von MockVirtualMethodsCommand durch eine Instanzierung Ihrer neuen Klasse.

Wir könnten uns auch eine Möglichkeit vorstellen, dieses Verhalten konfigurierbar zu machen, aber ich bin mir nicht sicher, ob die Nachfrage hoch genug ist, um dies zu rechtfertigen. Eine solche Änderung sollte meiner Meinung nach nicht auf die leichte Schulter genommen werden – eine feinkörnige Anpassung kann zu versehentlicher Komplexität führen. @ploeh , was

Ich gebe zu, dass ich dachte, dass die Testdoubles so konfiguriert sind, dass sie in AutoFixture zurückrufen, um einen Rückgabewert zu erhalten. AutoFixture verfügt bereits über einen Lifetime-Management-Mechanismus (über seine Freeze-Funktionen), daher finde ich es etwas überraschend, dass AutoConfiguredMoqCustomization seinen eigenen Lifetime-Manager implementiert und damit die von AutoFixture selbst bereitgestellte Steueroberfläche überschreibt.

Das ist ein sehr guter Punkt, ich habe nie so über Freeze nachgedacht. Das Verhalten der Anpassung jetzt zu ändern, wäre meiner Meinung nach eine bahnbrechende Änderung ... meinst du, es sollte in AutoFixture v4 geändert werden?

Ist es Verhalten, das wir in Tests dokumentiert oder irgendwie „versprochen“ haben?

Überraschenderweise nein. Ich war mir ziemlich sicher, dass ich das abgedeckt hatte, aber anscheinend habe ich es nicht getan. Zumindest konnte ich keinen Test finden, der dies abdeckt, und das Entfernen dieser Zeile führte nicht dazu, dass ein Test fehlschlug. IMO, es ist jedoch immer noch ein beobachtbares Verhalten, und es wird wahrscheinlich Code geben, der darauf basiert ...

Gutes Argument. Könnte es ein Konfigurationswert sein, den wir jetzt auf einen Wert setzen und ihn dann ändern, wenn wir zu AutoFixture 4 wechseln?

Einverstanden. Was genau meinen Sie in diesem Zusammenhang mit "Konfigurationswert"? Würde es ausreichen, es innerhalb der Klasse MockType auf einen const zu heben? ZB private const bool cacheReturnValues = true und dann if(cacheReturnValues) /**/

Ich gebe zu, es war eine Art Wegwerf-Kommentar, daher weiß ich nicht, ob es ohne zu viele Änderungen praktisch möglich wäre. Was ich aber meinte war folgendes:

@andreasnilsen möchte das Verhalten jetzt ändern, aber wir befürchten, dass dies eine bahnbrechende Änderung wäre. Wenn wir das Verhalten konfigurierbar machen, würden wir @andreasnilsen jetzt eine Möglichkeit geben, das Verhalten zu ändern, während wir keine anderen Clients

Wenn wir AutoFixture 4 einführen, ändern wir die Standardkonfiguration, sodass das Standardverhalten dann darin besteht, dass Rückgabewerte nicht zwischengespeichert werden. Oder vielleicht entfernen wir diese Option einfach...

Etwas wie ein boolescher cacheReturnValues könnte eine Möglichkeit sein, dies zu tun, aber wir müssten den Clients ermöglichen, den Wert zu ändern, damit er nicht private .

(Außerdem sollten wir enum anstelle von bool Betracht ziehen, es sei denn, wir sind uns absolut sicher, dass es nur genau zwei Werte geben wird.)

Ah, ich dachte zuerst, du meinst ein internes Flag, das in v4 leicht zu erkennen und zu ändern ist.

Die ersten beiden Ansätze, die mir in den Sinn kommen, sind:

  • Fügen Sie dem Konstruktor von AutoConfiguredMoqCustomization einfach einen booleschen Parameter (optional, aus Gründen der Abwärtskompatibilität) hinzu, der dann nach unten zu MockVirtualMethodsCommand und zum internen MockType.ReturnsUsingContext propagiert wird. Dies scheint:

    1. etwas verworren und

    2. zu _ad hoc_. Wenn wir der Anpassung weitere Konfigurationsparameter hinzufügen wollten, würde der Konstruktor zu komplex und schwer zu verwenden/zu warten.

  • Verwenden Sie das Parameterobjektmuster , um das obige Problem (ii) zu lösen.

Ich bin vorsichtig, Designentscheidungen zu treffen, die wir später bereuen und an denen wir festhalten könnten, daher wäre Ihr Fachwissen / Ihre Erfahrung bei der Wartung dieses Projekts sehr dankbar.

Ich dachte an so etwas wie eine Strategie ...

Ach ja, natürlich! Ich schätze, ich war auf einen "Konfigurationswert" fixiert und habe vergessen, einen Schritt zurückzutreten.

Es tut mir leid für die späte Antwort, ich war überfordert - ich werde mir das bald ansehen und mit einem Designvorschlag zurückkommen.

Kürzlich haben wir das Anpassungs-Refactoring durchgeführt, um Eigenschaften für die Anpassungs-Optimierung zu verwenden. Möglicherweise könnte diese Funktion wie folgt gesteuert werden (finden Sie den besseren Einstellungsnamen):
c# new AutoMoqCustomization { CacheCallResults = false }

Unter der Haube könnten wir das mit einer anderen Strategie umsetzen, wie oben empfohlen.

Markierung mit Sprung in Tag, da dies relativ einfach zu realisieren sein sollte.

@zvirja könntest du mir ein bisschen helfen und ich kann daran arbeiten. ich weiß einfach nicht wo ich anfangen soll :)

@micheleissa Danke für dein Interesse! Ich würde vorschlagen, einfach den AutoMoq Quellcode zu lesen und ihn zu debuggen, um die interne Mechanik zu verstehen. Es ist sehr klein, daher sollte es nicht viel Zeit in Anspruch nehmen...

Wenn Sie genauere Fragen haben, fragen Sie bitte 😉

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

zvirja picture zvirja  ·  22Kommentare

malylemire1 picture malylemire1  ·  12Kommentare

zvirja picture zvirja  ·  32Kommentare

zvirja picture zvirja  ·  13Kommentare

Euan-McVie picture Euan-McVie  ·  15Kommentare