web-dev-qa-db-ja.com

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

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

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の問題のリストで enhancement として発生した上記の問題を発見し、4.5リリースに割り当てられているようです(それがいつでも)。

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

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

100
Appulus

現時点での唯一の選択は、boolのセットアップにFooパラメーターを明示的に含めることだと思います。

デフォルト値を指定するという目的に反するとは思わない。デフォルト値はコードを呼び出すのに便利ですが、テストでは明示的にする必要があると思います。 boolパラメーターの指定は省略できます。将来、誰かがbのデフォルト値をtrueに変更するとどうなりますか?これはテストの失敗につながりますが(当然のことながら)、bfalseであるという隠された仮定のため、修正がより困難になります。 boolパラメーターを明示的に指定することには別の利点があります。テストの可読性が向上します。それらを通過する人は、2つのパラメーターを受け入れるFoo関数が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
    {
        ...
    }
}
75
Chris Mantle

今日この問題が発生したばかりで、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);
7
Gil Grossman