Das vollständig generische Moq-Setup mit einem Klassen-Proxy-Versuch löst die Meldung aus, dass spät gebundene Vorgänge C#

Ein Treffpunkt für C#-Programmierer
Guest
 Das vollständig generische Moq-Setup mit einem Klassen-Proxy-Versuch löst die Meldung aus, dass spät gebundene Vorgänge

Post by Guest »

Zu lösendes Problem
Ich versuche, mithilfe der Moq-Bibliothek eine Nachbildung der Schnittstelle ISomeService zu erstellen, die ihre eigentliche Implementierung SomeService umschließt< /code>.
Im Moment mache ich das manuell so:

Code: Select all

var instance = new SomeService();
var mock = new Mock();
mock.Setup(x => x.Run(It.IsAny()))
.Returns(x => instance.Run(x));
Es ruft eine echte Implementierung auf, sodass meine Tests zuverlässiger sind und ich von einem Mock wie Verify usw. profitiere. Das Problem ist, dass ich es für jede Methode und jeden Dienst implementieren muss, den ich verwende nicht der richtige Weg. Ich strebe eine vollautomatische Lösung an.
WAS ICH GEMACHT HABE
Was ich für Setup() habe Teil ist

Code: Select all

// (x)
var mockParameter = Expression.Parameter(typeof(T), "x");

// It.IsAny()
var isAnyMethod = typeof(It).GetMethod(nameof(It.IsAny));
var isAny = parameters.Select(x => Expression.Call(isAnyMethod.MakeGenericMethod(x.ParameterType))).ToArray();

// x.Run(It.IsAny())
mockCall = Expression.Call(mockParameter, method, isAny);
Und jetzt der lustige Teil. Wenn ich Lambda so definiere:

Code: Select all

// (x) => x.Run(It.IsAny())
var mockLambda = Expression.Lambda(mockCall, mockParameter);
Es erzeugt einen LambdaExpression und funktioniert nicht mit der Setup-Methodendefinition, die einen vollständig definierten Ausdruck erfordert:

Code: Select all

public ISetup Setup(Expression expression)
Ich kann Setup nicht direkt aufrufen, da ich den Typ von TResult nicht kenne, also greife ich offensichtlich auf Reflektion zurück:

Code: Select all

var setupMethod = typeof(Mock)
.GetMethods()
.Where(x => x.Name == nameof(mock.Setup) && x.GetParameters()[0].ParameterType.GetGenericArguments()[0].GetGenericTypeDefinition() == typeof(Func)).First()
.MakeGenericMethod(method.ReturnType);

var setupResult = setupMethod.Invoke(mock, new object[] { mockLambda });
aber ich erhalte eine Fehlermeldung

System.InvalidOperationException: „Spät gebundene Vorgänge können nicht für Typen oder Methoden ausgeführt werden.“ which ContainsGenericParameters is true.'

was Sinn macht, aber enttäuschend ist.
WAS ICH VERSUCHT HABE< /strong>
Ich habe versucht, das Ergebnis zu übertragen Typ zu Objekt Typ

Code: Select all

var converted = Expression.Convert(mockCall, typeof(object));
damit ich schreiben konnte

Code: Select all

// (x) => (object)x.Run(It.IsAny())
var mockLambda = Expression.Lambda(converted, mockParameter);
aber dies löst auch eine Ausnahme aus

System.ArgumentException: 'Unsupported expression: (object)x.Run( It.IsAny())'

Damit dies funktioniert, habe ich eine Reihe von else if-Anweisungen für Werttypen hinzugefügt, bei denen ich für einen bestimmten Ergebnistyp einen bestimmten Ausdruck zurückgebe aber das Es ist ein Albtraum, es aufrechtzuerhalten und zu erweitern. Für Klassen verwende ich Objekt und zumindest dieser Teil funktioniert.
Für benutzerdefinierte Werttypen habe ich eine generische Methode hinzugefügt

Code: Select all

void SetupUnsuportedMethod(MethodInfo methodInfo)
und der Benutzer muss das fehlende Setup selbst hinzufügen.
FRAGE[/b]
Gibt es eine Möglichkeit, diesen Code vollständig generisch zu gestalten? Vielleicht gibt es einen besseren Weg, dieses Problem zu lösen? Oder muss ich mich an diese fiese Sonst-wenn-Lösung halten?

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post