UT書いててハマった!!
UT書いてて、**Substitute.For<>**と**Substitute.ForPartsOf<>**の違いがよく分かっておらずハマりました。
NSubstituteって、あんまり日本語で書いた文献がなくて、スッと答えにたどり着きたいのに時間がかかるんだよなぁ。。。結局公式ドキュメントを見て、細かく仕様を理解しようとするっていう(ホントはこのやり方がが正しい←)
ということで、NSubstituteについて少し。
.NetにおけるMockライブラリNSubstitute
公式のドキュメントには、Nsubstituteとはなんぞやと以下のように書いてありました。
A friendly substitute for .NET mocking libraries
「.NETモックライブラリのフレンドリーな代替品」
※みんなの先生に訳していただきました。先生ありがとうございます。
雰囲気でなんとなく分かりましたね。とにかくフレンドリーなんです。次にいきましょう。(適当ですみません。)
**Substitute.For<>**は「Creating a substitute」に
**Substitute.ForPartsOf<>**は「Partial subs and test spies」に
それぞれ記載があります。目的別に目次が分かれているんですね。
Substitute.For<>
こんな感じで書き方が紹介されています。
var substitute = Substitute.For<ISomeInterface>();
This is how you’ll normally create substitutes for types. Generally this type will be an interface, but you can also substitute classes in cases of emergency.
差し替える対象は基本はInterfaceなんですが、緊急事態には普通のclassでも差し替えられるんですね。どんな時を思い描いているのでしょうか。緊急事態って。
// 例) IsomeInterfaceのGetIntValue()メソッドの結果を1に差し替える
substitute.GetIntValue().Returns(1);
こんな感じで、Substitute.Forしたインターフェースが実装しているメンバ関数の結果を差し替えることができます。
Substitute.ForPartsOf<>
Partial substitutes allow us to create an object that acts like a real instance of a class, and selectively substitute for specific parts of that object.
「部分的代替はあるクラスの実際のインスタンスかのように振る舞うオブジェクトを生成することができて、選択的にオブジェクトの一部を差し替えることができますよー。」
とな。
Substitute.For<>がクラスを丸ごと差し替えるのに対して、Substitute.ForPartsOf<>は部分的にクラスのメソッドの結果を差し替えるわけですね。
そして、やらかす。
じゃあ、おんなじ感じっしょーと既にSubstitute.ForPartsOf<>で定義されていたインスタンスに対してメソッドの結果の差し替えを行おうとしていました。
// あかーん例
var substitute = Substitute.For<ISomeInterface>();
substitute.GetIntValue().Returns(1);
よしよし、コンパイルエラーも出ないしOKっしょ。とテスト実行してみると、失敗。
差し替えが行われず、実際のインスタンスが使われてしまいました。
改めて公式ドキュメントへ
ムムム。。。と思い、公式ドキュメントを改めて眺めてみると、
If we had not used Configure() here before .ReadFile()(差し替えたいメソッド) then the real ReadFile method would have executed before we had a chance to override the behaviour. In some cases this may not be a problem, but if in doubt make sure you call Configure() first so NSubstitute knows you are configuring a call and don’t want to run any real code.
「差し替えたいメソッドの前に**Configure()**ってのを書いておかないと、動作をoverrideする前に実際のメソッドが実行されちゃうかもしれないよー。問題にならないケースもあるけど、確実に差し替えたいなら、**Configure()**ってのをとりあえず付けといて。そしたらNSubstituteは実際のコードを呼んで欲しくないんだなーって分かるから!」
そうなのかぁー。**Configure()**ってのが必要だったのね。。。失敬、失敬。
と思い、実際に書いてみると「そんなメソッド知らん」とコンパイルエラー。
The Configure() method is only available in NSubstitute 4.0 and above. For verisons prior to 4.0 we need to use When .. DoNotCallBase described below.
「Configure()は、NSubstitute 4.0以降しか使えないよ。それより前のバージョンの人はWhen .. DoNotCallBaseを使ってね☆」
When .. DoNotCallBaseを使って、無事にメソッドの差し替えができましたとさ。
つぶやき
partial substitutes are not generally recommended
一般的には非推奨みたいです。
**Substitute.For<>**の方を使えってことなんですね。