【Moq】Moqはメソッドチェーンでまるごとモック化できるよ
メソッドチェーンのモック化
IFoo -> IBar -> IBaz のようにinterfaceのプロパティが連結されている場合、 以下の2つのモック化は同等になります。
// setup var fooMock = new Mock<IFoo>(); var barMock = new Mock<IBar>(); var bazMock = new Mock<IBaz>(); // when fooMock.Setup(m => m.Bar).Returns(barMock.Object); barMock.Setup(m => m.Baz).Returns(bazMock.Object); bazMock.Setup(m => m.Message).Returns("Hello Redundant"); // then IFoo target = fooMock.Object; Assert.That(target.Bar.Baz.Message, Is.EqualTo("Hello Redundant")); Assert.That(target.Bar.Baz, Is.Not.Null);
↓
// setup var fooMock = new Mock<IFoo>(); // when fooMock.Setup(m => m.Bar.Baz.Message).Returns("Hello Chain"); // then IFoo target = fooMock.Object; Assert.That(target.Bar.Baz.Message, Is.EqualTo("Hello Chain"));
上部(以後Aパターン)のようにわざわざ、IFoo
, IBar
, IBaz
のMockを作る必要はなく、
下部(以後Bパターン)の fooMock.Setup(m => m.Bar.Baz.Message).Returns("Hello Chain");
のようにIFoo
からメソッドチェーンでまとめてモック化してくれるという話でした。
何が起こっているの?
どうやらAパターンの宣言でBパターンと同等になるようです。
後で検証コードを記載しますが、
target.Bar
に Mock<IBar>.Object
, target.Bar.Baz
にMock<IBaz>.Object
のインスタンスが割り当てられていました。
Setupで指定しない場合はdefault
以下の用にSetup
を実施しない場合はdefault、つまりnullを返します。
// setup var fooMock = new Mock<IFoo>(); // when // fooMock.Setup(m => m.Bar.Baz.Message).Returns("Hello Chain"); // then IFoo target = fooMock.Object; Assert.That(() => target.Bar.Baz.Message, Throws.TypeOf<NullReferenceException>());
検証コード
- NUnitで検証
IFoo
,IBar
,IBaz
のinterfaceも定義
雑感
Moqを使ったことない同僚の方に、自分のコードを参考にMoqを使ってもらったら、
上記のようにメソッドチェーンでまるごとモック化する使い方をされていて発覚しました。
Moq使いだして2年以上、全然気づきませんでした。。。 先入観って怖いですね(笑)。
それでは~