Ich habe eine bereits vorhandene Schnittstelle ...
public interface ISomeInterface
{
void SomeMethod();
}
und ich habe dieses intreface mit einem mixin erweitert ...
public static class SomeInterfaceExtensions
{
public static void AnotherMethod(this ISomeInterface someInterface)
{
// Implementation here
}
}
Ich habe eine Klasse, die das nennt und die ich testen möchte ...
public class Caller
{
private readonly ISomeInterface someInterface;
public Caller(ISomeInterface someInterface)
{
this.someInterface = someInterface;
}
public void Main()
{
someInterface.AnotherMethod();
}
}
und ein Test, bei dem ich die Schnittstelle verspotten und den Aufruf der Erweiterungsmethode überprüfen möchte ...
[Test]
public void Main_BasicCall_CallsAnotherMethod()
{
// Arrange
var someInterfaceMock = new Mock<ISomeInterface>();
someInterfaceMock.Setup(x => x.AnotherMethod()).Verifiable();
var caller = new Caller(someInterfaceMock.Object);
// Act
caller.Main();
// Assert
someInterfaceMock.Verify();
}
Das Ausführen dieses Tests erzeugt jedoch eine Ausnahme ...
System.ArgumentException: Invalid setup on a non-member method:
x => x.AnotherMethod()
Meine Frage ist, gibt es eine gute Möglichkeit, den Mixin-Aufruf zu verspotten?
c#
unit-testing
mocking
extension-methods
moq
Russell Giddings
quelle
quelle
Antworten:
Sie können die statische Methode (daher die Erweiterungsmethode) mit dem Mocking-Framework nicht "direkt" verspotten. Sie können Moles ( http://research.microsoft.com/en-us/projects/pex/downloads.aspx ) ausprobieren , ein kostenloses Tool von Microsoft, das einen anderen Ansatz implementiert. Hier ist die Beschreibung des Tools:
Sie können Moles mit jedem Testframework verwenden (davon ist es unabhängig).
quelle
Ich habe einen Wrapper verwendet, um dieses Problem zu umgehen. Erstellen Sie ein Wrapper-Objekt und übergeben Sie Ihre verspottete Methode.
Siehe Verspotten statischer Methoden für Unit-Tests von Paul Irwin, es gibt schöne Beispiele.
quelle
Ich stellte fest, dass ich das Innere der Erweiterungsmethode entdecken musste, für die ich die Eingabe verspotten wollte, und verspotten musste, was in der Erweiterung vor sich ging.
Ich habe die Verwendung einer Erweiterung als direktes Hinzufügen von Code zu Ihrer Methode angesehen. Dies bedeutete, dass ich mich über das lustig machen musste, was in der Erweiterung passiert, und nicht über die Erweiterung selbst.
quelle
Sie können eine Testschnittstelle verspotten, die von der realen erbt und ein Mitglied mit derselben Signatur wie die Erweiterungsmethode hat.
Sie können dann die Testschnittstelle verspotten, die echte zum Verspotten hinzufügen und die Testmethode im Setup aufrufen.
Ihre Implementierung des Mocks kann dann jede gewünschte Methode aufrufen oder einfach überprüfen, ob die Methode aufgerufen wird:
Vielen Dank an die Håvard S-Lösung in diesem Beitrag für die Implementierung eines Modells, das zwei Schnittstellen unterstützt. Sobald ich es gefunden hatte, war es ein Kinderspiel, es mit der Testschnittstelle und der statischen Methode anzupassen.
quelle
SomeNotAnExtensionMethod
und zeigenSomeNotAnExtensionMethod
? Ich habe jetzt eine Idee, wie man eine Signatur für eine Erweiterungsmethode innerhalb einer Schnittstelle erstellt ...iReal
ParameterSomeExtensionMethod
im Fall vonITest
? Wenn Sie es als ersten Parameter übergeben, wie richten Sie es dann ein?Setup( x=> x.SomeExtensionMethod(x, ...)
Dies führt zu einer Laufzeitausnahme.object _mockCache = whatever
... `Setup (x => x.SomeExtensionMethod (...) .. Callback (() => Sie können Zugriff auf _mockCache hier);)Mit JustMock können Sie eine Erweiterungsmethode leicht verspotten . Die API entspricht der Verspottung einer normalen Methode. Folgendes berücksichtigen
Verwenden Sie Folgendes, um diese Methode zu arrangieren und zu überprüfen:
Hier ist auch ein Link zur Dokumentation: Extension Methods Mocking
quelle
Ich verwende gerne den Wrapper (Adaptermuster), wenn ich das Objekt selbst umhülle. Ich bin mir nicht sicher, ob ich das zum Umschließen einer Erweiterungsmethode verwenden würde, die nicht Teil des Objekts ist.
Ich verwende eine interne Lazy Injectable-Eigenschaft vom Typ Action, Func, Predicate oder delegate und erlaube das Injizieren (Austauschen) der Methode während eines Unit-Tests.
Dann rufen Sie die Func anstelle der eigentlichen Methode auf.
Ein vollständigeres Beispiel finden Sie unter http://www.rhyous.com/2016/08/11/unit-testing-calls-to-complex-extension-methods/
quelle
Wenn Sie also Moq verwenden und das Ergebnis einer Erweiterungsmethode verspotten möchten, können Sie es
SetupReturnsDefault<ReturnTypeOfExtensionMethod>(new ConcreteInstanceToReturn())
für die Instanz der Scheinklasse verwenden, die die Erweiterungsmethode enthält, die Sie verspotten möchten .Es ist nicht perfekt, aber für Unit-Testzwecke funktioniert es gut.
quelle