明示的に指定したり、オーバーロードを使用したりせずに、シグニチャーにオプションの引数を持つメソッドをMoqするにはどうすればよいですか?


119

次のインターフェースがあるとします。

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

Moqを使用してそれを模擬しようとしています:

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

コンパイル時に次のエラーが発生します。

式ツリーには、オプションの引数を使用する呼び出しまたは呼び出しを含めることはできません

上記の問題はMoqの問題リストの拡張として発生したことがわかり、4.5リリースに割り当てられているようです(それがいつでも)。

私の質問は、上記の問題がすぐに修正されない場合、どうすればよいですか?私のオプションは、それをモックするたびにオプションのパラメーターのデフォルト値を明示的に設定する(最初の場所で1を指定するポイントを無効にする)か、またはブール値なしでオーバーロードを作成する(私がしたように)だけですか? C#4より前)?

または、誰かがこの問題を克服するためのより賢い方法に出くわしましたか?


5
2番目のパラメーターにIt.IsAny <bool>()を指定するだけで十分でしょうか?
Paul d'Aoust 2013年

一年半後にこれはまだ本当です...
Mukus

@ Mukus、PRをドロップしてください、仲間。
IamDOM

回答:


91

現時点での唯一の選択肢boolは、の設定にパラメータを明示的に含めることですFoo

デフォルト値を指定する目的にそぐわないとは思いません。デフォルト値はコードを呼び出すのに便利ですが、テストでは明示する必要があると思います。boolパラメータの指定を省略できるとしましょう。将来、誰かがのデフォルト値をbに変更するとtrueどうなりますか?これは失敗テスト(と当然のように)につながる、しかし、彼らはので、隠された仮定の修正がより困難になりますbですfalseboolパラメータを明示的に指定することには、テストの読みやすさが向上するという別の利点があります。それらを通過する誰かFooは、2つのパラメーターを受け入れる1つの関数があることをすぐに理解します。それは私の2セントです。少なくとも:)

モックするたびに指定する場合は、コードを複製しないでください。関数内でモックを作成または初期化して、変更点が1つだけになるようにします。本当にやりたい場合は、Fooこの初期化関数にのパラメーターを複製することで、Moqの明らかな欠点を克服できます。

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

1
すばらしい答え。私はすでに先に進み、モックでそれを明示的に指定しましたが、あなたの答えは、なぜ私がこのようにすべきなのかを非常に明確かつ論理的な方法で確認します。ありがとう、@ Chris。
Appulus 2012年

9
デフォルトのパラメータを変更すると、テストが失敗するはずです。デフォルトが変更されたときにテストが失敗しないことは、テストが悪い兆候である可能性があります。コードはデフォルトを使用する場合がありますが、テストは使用しませんか?
Pop Catalin 2013

しばらくの間、インターフェイス(DapperのIDConnection)をモックしようとするときにMoqでこのアプローチを試しましたが、それでも同じエラーが発生します。何かアイデアはありますか?サンプル行:mockDB.Setup(x => x.Query <MyObject>(It.IsAny <string>()、It.IsAny <DynamicParameters>()、It.IsAny <IDbTransaction>()、false、600))。 Return(new List <MyObject>()); 最後の2つの値は、設定しているメソッドのオプションのパラメーターです。
Raelshark 2013

4
あらー!恐ろしいif (!x) {} else {}アンチパターン:)
nicodemus13 14

1
@ nicodemus13はい。ただし、コード例を質問のOPの例にできるだけ近づけようとしました。私は必ずしもそれを擁護するつもりはありません:)
Chris Mantle

8

今日この問題が発生したばかりで、Moqはこの使用例をサポートしていません。したがって、この場合はメソッドをオーバーライドするだけで十分です。

public interface IFoo
{
    bool Foo(string a);

    bool Foo(string a, bool b);
}

これで両方の方法が利用可能になり、この例は機能します:

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

2

Moqバージョン4.10.1を使用して、私は次のことができました

インターフェースあり:

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

そしてモック

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

最初のパラメーターでFooの呼び出しを解決します

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.