Frage Kannst du mir helfen, Moq Callback zu verstehen?


Mit Moq und angeschaut Callback aber ich konnte kein einfaches Beispiel finden, um zu verstehen, wie man es benutzt.

Haben Sie ein kleines Arbeits-Snippet, das deutlich erklärt, wie und wann es zu verwenden ist?


76
2018-05-14 09:44


Ursprung


Antworten:


Schwer zu schlagen https://github.com/Moq/moq4/wiki/Quickstart

Wenn das nicht klar genug ist, würde ich das einen Doc-Bug nennen ...

EDIT: Als Antwort auf Ihre Klärung ...

Für jede verspottete Methode Setup du leistest, kannst du Dinge anzeigen wie:

  • Einschränkungen für Eingaben
  • der Wert für / way, in dem der Rückgabewert (falls vorhanden) abgeleitet werden soll

Das .Callback Der Mechanismus sagt: "Ich kann es jetzt nicht beschreiben, aber wenn ein Anruf in dieser Form stattfindet, ruf mich zurück und ich werde tun, was getan werden muss". Als Teil derselben fließenden Aufrufkette können Sie steuern, ob das Ergebnis (falls vorhanden) über zurückgegeben wird .Returns"In den QS-Beispielen ist ein Beispiel, dass sie den zurückgegebenen Wert jedes Mal erhöhen.

Im Allgemeinen werden Sie einen Mechanismus wie diesen nicht sehr oft brauchen (xUnit Test Patterns haben Begriffe für Anti-Patterns der Art Conditional Logic In Tests), und wenn es eine einfachere oder eingebaute Möglichkeit gibt, das zu finden, was Sie brauchen, sollte es sein bevorzugt verwendet.

Teil 3 von 4 in Justin Etheredges Moq-Reihe deckt es ab und Hier gibt es ein weiteres Beispiel für Rückrufe


65
2018-05-14 14:06



Im Folgenden finden Sie ein Beispiel für die Verwendung eines Callbacks zum Testen einer Entität, die an einen Datenservice gesendet wird, der eine Einfügung verarbeitet.

var mock = new Mock<IDataService>();
DataEntity insertedEntity = null;

mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
           .Callback((DataEntity de) => insertedEntity = de);

Alternative generische Methodensyntax:

mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
           .Callback<DataEntity>(de => insertedEntity = de);

Dann kannst du sowas testen

Assert.AreEqual("test", insertedEntity.Description, "Wrong Description");

46
2018-01-30 21:21



Es gibt zwei Arten von Callback in moq. Man passiert, bevor der Anruf zurückkehrt; der andere passiert, nachdem der Anruf zurückkehrt.

var message = "";
mock.Setup(foo => foo.Execute(arg1: "ping", arg2: "pong"))
    .Callback((x, y) =>
    {
        message = "Rally on!";
        Console.WriteLine($"args before returns {x} {y}");
    })
    .Returns(message) // Rally on!
    .Callback((x, y) =>
    {
        message = "Rally over!";
        Console.WriteLine("arg after returns {x} {y}");
    });

In beiden Callbacks können wir:

  1. Überprüfen Sie die Argumente der Methode
  2. Methodenargumente aufnehmen
  3. Ändern Sie den Kontextstatus

6
2018-01-26 01:10



Callback ist einfach ein Mittel, um jeden benutzerdefinierten Code auszuführen, den Sie wünschen, wenn ein Aufruf an eine der Methoden des Mocks erfolgt. Hier ist ein einfaches Beispiel:

public interface IFoo
{
    int Bar(bool b);
}

var mock = new Mock<IFoo>();

mock.Setup(mc => mc.Bar(It.IsAny<bool>()))
    .Callback<bool>(b => Console.WriteLine("Bar called with: " + b))
    .Returns(42);

var ret = mock.Object.Bar(true);
Console.WriteLine("Result: " + ret);

// output:
// Bar called with: True
// Result: 42

Ich bin kürzlich auf einen interessanten Anwendungsfall gestoßen. Angenommen, Sie erwarten einige Aufrufe zu Ihrem Schein, aber sie geschehen gleichzeitig. Sie haben also keine Möglichkeit, die Reihenfolge zu kennen, in der sie angerufen werden, aber Sie möchten wissen, welche Anrufe erwartungsgemäß ausgeführt wurden (unabhängig von der Reihenfolge). Sie können so etwas tun:

var cq = new ConcurrentQueue<bool>();
mock.Setup(f => f.Bar(It.IsAny<bool>())).Callback<bool>(cq.Enqueue);
Parallel.Invoke(() => mock.Object.Bar(true), () => mock.Object.Bar(false));
Console.WriteLine("Invocations: " + String.Join(", ", cq));

// output:
// Invocations: True, False

Übrigens lassen Sie sich nicht durch das irreführende "Vorher" verwirren Returns" und danach Returns"Unterscheidung. Es ist nur eine technische Unterscheidung, ob Ihr benutzerdefinierter Code nachlaufen wird Returns wurde evaluiert oder vorher. In den Augen des Aufrufers werden beide ausgeführt, bevor der Wert zurückgegeben wird. In der Tat, wenn die Methode ist void-Rückkehr Sie können nicht einmal anrufen Returns und doch funktioniert es genauso. Für weitere Informationen siehe https://stackoverflow.com/a/28727099/67824.


2
2017-08-10 11:10



Zusätzlich zu den anderen guten Antworten hier habe ich es benutzt, um Logik durchzuführen, bevor eine Ausnahme ausgelöst wurde. Ich musste zum Beispiel alle Objekte speichern, die zur späteren Verifizierung an eine Methode übergeben wurden, und diese Methode (in einigen Testfällen), um eine Ausnahme auszulösen. Berufung .Throws(...)auf Mock.Setup(...) überschreibt die Callback() Aktion und ruft es nie an. Indem Sie jedoch eine Ausnahme innerhalb des Callbacks auslösen, können Sie immer noch all die guten Dinge tun, die ein Callback anbieten muss, und dennoch eine Ausnahme auslösen.


1
2018-01-10 03:03