2012-10-18 2 views
82

die folgende Schnittstelle Gegeben:Wie moq ich Moq eine Methode, die ein optionales Argument in seiner Signatur hat, ohne es explizit anzugeben oder eine Überladung zu verwenden?

public interface IFoo 
{ 
    bool Foo(string a, bool b = false); 
} 

Der Versuch, sie zu verspotten Moq mit:

var mock = new Mock<IFoo>(); 
mock.Setup(mock => mock.Foo(It.IsAny<string>())).Returns(false); 

bei der Kompilierung die folgende Fehlermeldung erhalten:

Ein Ausdruck Baum keinen Anruf enthalten oder Aufruf mit optionalen Argumenten

Ich habe festgestellt, das Problem oben als enhancement in Moq Liste der Probleme ausgelöst und es scheint, die 4.5-Version zugeordnet werden (wann immer das ist).

Meine Frage ist: Was soll ich tun, wenn das oben genannte nicht in nächster Zeit behoben wird? Sind meine Optionen nur, um entweder den Standardwert des optionalen Parameters jedes Mal explizit zu setzen, wenn ich ihn verspotte (was den Punkt, an dem man einen spezifiziert, vereitelt) oder eine Überladung ohne Bool zu erzeugen (wie ich es getan hätte) vor C# 4)?

Oder hat jemand einen schlaueren Weg gefunden, dieses Problem zu lösen?

+4

Wäre es sinnvoll sein, nur It.IsAny () für den zweiten Parameter angeben? –

+0

Eineinhalb Jahre später ist das immer noch wahr. – Mukus

Antwort

63

Ich glaube, dass Ihre einzige Wahl im Moment ist, den Parameter bool explizit in das Setup für Foo aufzunehmen.

Ich glaube nicht, dass es den Zweck der Angabe eines Vorschlagswerts besiegt. Der Standardwert ist ein Vorteil für den Aufruf von Code, aber ich denke, dass Sie in Ihren Tests explizit sein sollten. Angenommen, Sie könnten den Parameter bool auslassen. Was passiert, wenn in Zukunft jemand den Standardwert b zu true ändert? Dies führt zu fehlerhaften Tests (und zwar zu Recht), aber sie werden schwieriger zu beheben sein, weil die versteckte Annahme bfalse ist. Die explizite Angabe des Parameters bool hat einen weiteren Vorteil: Es verbessert die Lesbarkeit Ihrer Tests. Jemand, der sie durchgeht, weiß schnell, dass es eine Foo Funktion gibt, die zwei Parameter akzeptiert. Das sind meine 2 Cent, mindestens :)

Um es jedes Mal zu spezifizieren, wenn Sie es verspotten, kopieren Sie den Code nicht: Erstellen Sie und/oder initialisieren Sie den Schein in einer Funktion, so dass Sie nur einen einzigen Punkt der Änderung haben . Wenn Sie wirklich wollen, können Sie überwinden Moq scheinbare Kurz kommen hier durch Duplizieren Foo ‚s Parameter in diese Initialisierungsfunktion:

public void InitFooFuncOnFooMock(Mock<IFoo> fooMock, string a, bool b = false) 
{ 
    if(!b) 
    { 
     fooMock.Setup(mock => mock.Foo(a, b)).Returns(false); 
    } 
    else 
    { 
     ... 
    } 
} 
+1

Ausgezeichnete Antwort; Ich habe es bereits in meinen Mocks explizit ausgeführt und spezifiziert, aber Ihre Antwort bestätigt auf sehr klare und logische Weise, warum ich es so machen sollte. Danke, Chris. – Appulus

+7

Ändern eines Standardparameters "sollte" Tests brechen. Wenn Tests nicht fehlschlagen, wenn ein Standard geändert wird, kann dies ein Zeichen für schlechte Tests sein. Der Code kann die Standardwerte verwenden, aber die Tests nicht? –

+0

Schon eine Weile, aber ich habe diesen Ansatz mit Moq ausprobiert, als ich versuchte, eine Schnittstelle zu verspotten (IDConnection in Dapper) und ich bekomme immer noch den gleichen Fehler. Irgendwelche Ideen warum? Beispielzeile: mockDB.Setup (x => x.Query (It.IsAny (), It.IsAny (), It.IsAny (), false, 600)). Rückgabe (neue Liste ()); Die letzten beiden Werte sind die optionalen Parameter für die Methode, die ich einrichte. – Raelshark

5

Genau dieses Problem heute begegnet, ist Moq nicht diesen Anwendungsfall unterstützen. So scheint es, dass das Überschreiben der Methode für diesen Fall ausreichend wäre.

public interface IFoo 
{ 
    bool Foo(string a); 

    bool Foo(string a, bool b); 
} 

Jetzt sind beide Methoden zur Verfügung, und dieses Beispiel funktionieren würde:

var mock = new Mock<IFoo>(); 
mock.Setup(mock => mock.Foo(It.IsAny<string>())).Returns(false); 
Verwandte Themen