.NET Core 1. システムエンジニアリング 実装技術
.NET Core(C#): MoqのSetupProperty()/SetupGet()/SetupSet()の違い

はじめに
- 次の環境を使用して動作確認しています。
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()で準備したプロパティは、一般的なプロパティと同様に値の設定や取得が可能です。
プロパティに設定されている最終的な値が期待したものかを検証することができます。
var 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()で検証できます。
var 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); // NG
Assert.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()を使用する必要があります。
- プロパティ(やメソッド)の実行回数を細かい条件で検証する場合は、Mock.VerifySet(), Mock.VerifyGet()を使用します。Verify()とは異なり、検証対象のプロパティや期待値を直接指定するので、SetupGet()/SetupSet()は不要です。
var 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); // NG
Assert.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) |
-.NET Core, 1. システムエンジニアリング, 実装技術
関連記事
-
-
Apache HttpClientの通信内容をダンプ
アプリやミドルウェの動作の正常性確認や問題発生時の問題切り分けのために、HTTPリクエストやレスポンスのヘッダやボディを確認したい場合がある。Java系のアプリではApacheのHttpClientが …
-
-
ASP.NET Core: エラーメッセージの日本語化
ASP.NET Coreでは入力値を検証するための[Required]等の検証属性が提供されていますが、エラーメッセージが英語になっています。 検証属性以外でも画面の実装方法によってはモデルバインディ …
-
-
JavaにおけるFileとPathを使ったパス操作
サーバ側でのzipファイルの解凍等の際に、意図しないディレクトリやファイル(ディレクトリトラバーサル攻撃)へのアクセスを防ぐための検証として、絶対パスを正規化したい場合がある。 Fileクラスを使った …
-
-
mybatis-generatorプラグインの実装方法
mybatis-generatorを使うことで、各テーブルを操作するためのクラス群を容易に準備することができます。しかしながら、mybatis-generatorが提供する機能では、システム開発で求め …
-
-
slf4jで独自ログ項目を追加(MDC)
はじめに 業務要件、障害発生時の処理追跡や証跡等、ログ出力に特定項目を含めたい場合があります。 共通のログ出力ユーティリティやライブラリを作って、その中でログ出力内容を変更しても良いのですが、MDC( …