はじめに
- 次の環境を使用して動作確認しています。
OS Windows 10(64ビット) IDE Microsoft Visual Studio Community 2019(16.8.5) + C#(8.0) パッケージ Microsoft.NET.Test.Sdk 16.10.0
xunit 2.4.1
xunit.runner.visualstudio 2.4.3
Moq 4.16.1 - 完全なソースコードはこちらで公開しています。
- xUnitのAssertの使い方はこちらで紹介しています。
- Moq関連の情報
SetupProperty()/SetupGet()/SetupSet()の違い
- SetupProperty()、SetupSet()/SetupGet()と併せて使用されるVerify(), VerifyGet()/VerifySet()の違いは次の通りです。
SetupSet()/SetupGet()系は誤解を招く場合があるので、基本的にはSetupProperty()を使用することを強くおすすめします。項目 SetupProperty() SetupSet(), SetupGet()
,Verify(), VerifyGet()/VerifySet()用途 追跡可能なプロパティの準備 プロパティ値の設定・取得回数の検証 設定値の保持と取得 可能 不可 最新のプロパティ値の検証 可能 不可 過去のプロパティ値の検証 不可 可能
(値毎の回数を検証可、順番の検証不可)プロパティ値の取得回数 不可 可能 プロパティ値の設定回数 不可 可能 - SetupProperty()で準備したプロパティは、一般的なプロパティと同様に値の設定や取得が可能です。
プロパティに設定されている最終的な値が期待したものかを検証することができます。1234567var targetMock = new Mock<ITarget>();ITarget target = targetMock.Object;targetMock.SetupProperty(o => o.StrProp);target.StrProp = "test";Assert.Equal("test", target.StrProp); - プロパティ(やメソッド)が実行されたかは、SetupGet()/SetupSet()とMock.Verify()で検証できます。12345678910111213141516171819202122var targetMock = new Mock<ITarget>();ITarget target = targetMock.Object;// 一括検証(Verify)の対象とするためにVerifiable()を指定targetMock.SetupGet(o => o.StrProp).Verifiable();targetMock.SetupSet(o => o.IntProp = 100) // 検証時の期待値(初期値設定ではない!).Verifiable();_ = target.StrProp;target.IntProp = 1;target.IntProp = 100;target.IntProp = 100;target.IntProp = 200;targetMock.Verify(); // 一括検証(検証対象を纏めて検証)// 値を保持していないので、最終的な値を検証できない。//Assert.Equal(200, target.IntProp); // NGAssert.Equal(0, target.IntProp);
- プロパティ値の取得が実行されたか(getter呼び出し回数が1回以上)を検証する場合、SetupGet()で対象プロパティを指定します。プロパティ値に特定値が設定されたか(setter呼び出し回数が1回以上)を検証する場合、SetupSet()で対象プロパティと期待値を指定します。
また、Verify()の検証対象とするために、各SetupGet()/SetupSet()に対して、Verifiable()を実行する必要があります。 - SetupSet()で指定する値は、次のように2重、3重に誤解を招くので、利用には注意が必要です。
- 期待値が「プロパティの初期値」のように見える。
- 検証では「プロパティに期待値が1回以上設定されたことを検証」するのであって、「プロパティ値と期待値の一致を検証」するわけではありません。(上記のサンプルでは、IntPropプロパティ値として100を検証していますが、一度でも100が設定されれば良いので、最終的に200が設定されても検証が成功してしまいます。)
- SetupSet()を実行すると、SetupProperty()のようにプロパティ値が保持されるように見えます。実際には「プロパティ値に期待値が設定されたか」の情報しかなく、プロパティ値は保持されていません。(上記のサンプルでは、IntPropに100や200を設定していますが、取得できるプロパティ値は既定値0のみです。)
- Mock.Verify()では「プロパティのgetter/setterが1回以上実行されたかどうか」の検証しかできません。1回のみ実行された、2回以上実行された、実行されていない、等の細かい条件を指定する場合は、次のMock.VerifyGet(), Mock.VerifySet()を使用する必要があります。
- プロパティ値の取得が実行されたか(getter呼び出し回数が1回以上)を検証する場合、SetupGet()で対象プロパティを指定します。プロパティ値に特定値が設定されたか(setter呼び出し回数が1回以上)を検証する場合、SetupSet()で対象プロパティと期待値を指定します。
- プロパティ(やメソッド)の実行回数を細かい条件で検証する場合は、Mock.VerifySet(), Mock.VerifyGet()を使用します。Verify()とは異なり、検証対象のプロパティや期待値を直接指定するので、SetupGet()/SetupSet()は不要です。12345678910111213141516var targetMock = new Mock<ITarget>();ITarget target = targetMock.Object;_ = target.StrProp;target.IntProp = 1;target.IntProp = 100;target.IntProp = 100;target.IntProp = 200;targetMock.VerifyGet(o => o.StrProp); // 1回のみ(既定)targetMock.VerifySet(o => o.IntProp = 100, Times.Exactly(2)); // 2回targetMock.VerifySet(o => o.IntProp = 300, Times.Never); // 0回// 値を保持していないので、最終的な値を検証できない。//Assert.Equal(200, target.IntProp); // NGAssert.Equal(0, target.IntProp);
- プロパティ値の取得回数、プロパティに設定された値とその回数を検証できますが、同様にプロパティ値を保持しないので最終的なプロパティ値を検証できません。
- 指定可能な実行回数(Times)は次通りです。
(”n”は実行回数、”a”, “b”は実行回数の条件を決定するための引数)項目 説明 Times.AtLeast(a) 最小回数(n >= a) Times.AtLeastOnce 1回以上(n >= 1) Times.AtMost(a) 最大回数(n <= a) Times.AtMostOnce 最大1回=0回か1回(n <= 1) Times.Between(a, b) a 回からb 回の間(a <= n <= b) Times.Exactly(a) a 回(n = a) Times.Never 0回(n = 0) Times.Once 1回(n = 1)