2014年11月26日水曜日

移行サンプル:Telerik JustMock によるモック化① final メソッドのモック化 - from "Prig: Open Source Alternative to Microsoft Fakes" Wiki -

まとまってきたドキュメントを日本語の記事にもしておくよシリーズ第 5 段!(元ネタ:Prigwiki より、MIGRATION: Final Mocking by Telerik JustMock。同シリーズの他記事:1 2 3 4

やっと折り返し地点ですね。今回からは 3 回に渡る JustMock の公式ドキュメントにあるサンプルを実装するシリーズとなります。まずは、「Final Mocking samples」を Prig に移行してみましょう。


以下の記事、ライブラリを使用/参考にさせていただいています。この場を借りてお礼申し上げます m(_ _)m
Using Jekyll with Pages - GitHub Help
Can I share a Microsoft Fakes unit test with a developer using Visual Studio Professional - Stack Overflow
shim a sealed class singleton method and with MS Fakes - Stack Overflow
Search - GitHub Anonymously Hosted DynamicMethods Assembly
API Hooking with MS Detours - CodeProject
Incorrect solution build ordering when using MSBuild.exe - The Visual Studio Blog - Site Home - MSDN Blogs
visual studio 2010 - How do I target a specific .NET project within a Solution using MSBuild from VS2010 - Stack Overflow
Advanced Usage | JustMock Documentation
.net - Is there any free mocking framework that can mock static methods and sealed classes - Stack Overflow
Modern ASP.NET Webskills by @calebjenkins





目次

準備
このサンプルでは、シリーズということもあり、1 つのソリューションに複数のプロジェクトを追加するという構成を採っています。





なお、この例は、間接的に呼び出される対象が、GAC に登録されていない Assembly に含まれており、以前の例(MolesFakes)とは異なることに注意してくださいね。

これまでは Package Manager Console で間接スタブを作成する手順を実施しても問題ありませんでしたが、今後は、PowerShell(コンソール)を使えるようになることを推奨します。Package Manager Console は、仕様上、ネストしたプロンプトをサポートしていません。従って、1 度間接対象の解析を行うために Assembly を読み込むと、2 度とその Assembly を解放できないという問題があるのです。そもそも、いつも使う機能である、オートコンプリート、コマンド履歴なども PowerShell(コンソール)のものより機能的に劣ります。間接設定の追加やテストの実行時は Package Manager Console を使い、Assembly の解析時は PowerShell(コンソール)を使うということが、効率が良いでしょう。

※注※:以下の解説で、PM> で始まるコマンドは Package Manager Console で実行しますが、PS> で始まるコマンドは PowerShell(コンソール)で実行することに注意してください。

FinalMockingMigration をビルド後、出力ディレクトリを開き、以下のコマンドを実行します。プロジェクトがいくつもありますので、対象のテストプロジェクトを Default project: として選択することをお忘れなく:

ちなみに、padd -af は、Add-PrigAssembly -AssemblyFrom のエイリアスです。GAC に登録されていない Assembly の間接スタブ設定を追加する場合、コマンドの引数にフルパスを引き渡す必要があることに注意してください。PowerShell(スクリプト言語)では、コマンド (dir <target file>).FullName でフルファイルパスを取得することができます。FinalMockingMigrationTest に FinalMockingMigration.v4.0.30319.v1.0.0.0.prig が追加されれば成功です。

さて、次は、FinalMockingMigration の出力ディレクトリ上で PowerShell(コンソール)を実行し、Assembly を解析しましょう。Windows 8 を使っているのであれば、エクスプローラで対象のディレクトリを表示中、Alt、F、R のキーコンビネーションが便利ですよね。現在の位置を確認したら、ネストしたプロンプトを開始します:

Package Manager Console で利用が可能になっている種々のコマンド(Find-IndirectionTarget や Get-IndirectionStubSetting など)は、Prig をインストール後、モジュール $(SolutionDir)\packages\Prig.\tools\Urasandesu.Prig に配置されます。なので、それを PowerShell(コンソール)にインポートします:

GAC に登録していない Assembly を読み込みたい場合、System.Reflection.Assembly.LoadFrom(string) にフルパスを引き渡す必要があります。取得には・・・って、ちょっと前にやりましたね (^^ゞ:

Assembly を読み込み後、変数に設定します。ところで、履歴から実行したコマンドを呼び出し、ちょっと変更して再実行するという流れは PowerShell(コンソール)の真骨頂だと思います。Package Manager Console で同じことをしようものなら、重複した履歴を延々と遡る必要があったり、オートコンプリートによる意図しない消去を食らったりすることになるでしょう。ストレスがマッハになること請け合いです (-_-;):

GetTypes で型を確認すると、上から 3 つが対象ということがわかります。それらに対し、前のサンプルと同様のフィルタを掛けてみましょう:

結果が良さそうであれば、間接スタブ設定に変換し、クリップボードにコピーします。なお、解析が終わった Assembly を解放したい場合は、ネストしたプロンプトを終了すれば OK です。

Visual Studio に戻り、FinalMockingMigration.v4.0.30319.v1.0.0.0.prig に間接スタブ設定を貼り付けます。ビルドは通りましたか?それでは、ちょっと長くなりましたが、実際の移行を行っていきましょう!





Assert Final Method Setup
Fakes のサンプルでも言いましたが、Prig は Mock Object としての機能を持っていませんので、Moq のような別のモックフレームワークと一緒に使うことを推奨しています。しかし、どうも JustMock のサンプルは、単に Test Stub としての振る舞いが紹介されているだけのものが大半ですので、Prig のサンプルもそれと一貫性を持たせるようにしました:

はじめに、final メソッドの戻り値を入れ替えてみましょう:

fooProxy.EchoInt32().Body = (@this, arg1) => 10; で、Prig は、その final メソッドを、定数 10 を返す処理に入れ替えています。大丈夫ですよね。次、行ってみましょう!





Assert Property Get
final プロパティを入れ替えるサンプルです:

fooProxy.FooPropGet().Body = @this => "bar"; で、Prig は、その final プロパティを、定数 bar を返す処理に入れ替えています。どんどん行きますよ (^O^)





Assert Property Set
final プロパティのセッターを検証するサンプルです。これは Moq を使ったほうが簡単そうですね:

Telerik.JustMock.Behavior.Strict は、Moq.MockBehavior.Strict にあたります。従って、Setup で指定した条件を満たさない引数で対象のメンバーを呼び出した場合、MockException をスローするようになります。





Assert Method Overloads
各 final メソッドのオーバーロードを入れ替えてみましょう。間接スタブ設定を正しく追加していれば、特に迷うことは無いはずです:

特に問題は無いですよね?次に進みましょう。





Assert Method Callbacks
イベントとしてのコールバックを置換することを説明する例です。Moles の例で紹介しましたが、実装には若干のテクニックが必要です:

実装は以下の流れになります:
  1. fooProxy.AddOnEchoCallbackEchoEventHandler().Body = (@this, value) => handler += value; のように、入れ替えたいイベントの += 演算子を乗っ取り、渡されたハンドラ(value)をテストのためのデリゲート(handler)に紐付ける。
  2. 元のイベントを発行したいタイミングで、手順 1 で紐づけたデリゲート(handler)を代わりに実行する。
これで、元のイベントを発火することと同じ効果を得ることができるようになります。





Assert Generic Types and Methods
ジェネリックな型とメソッドを入れ替える例です:

ね、簡単でしょう?これに関しては、以前の記事で解説したジェネリックのサポートも、合わせてご覧いただければと思います。



2014年11月23日日曜日

デフォルトの振る舞い - from "Prig: Open Source Alternative to Microsoft Fakes" Wiki -

まとまってきたドキュメントを日本語の記事にもしておくよシリーズ第 4 段!(元ネタ:Prigwiki より、FEATURES: Default Behavior。同シリーズの他記事:1 2 3

自動化されたテストで既存の振る舞いを囲う時、そのメソッドが呼び出されているかどうかだけを、単にチェックしたくなることがあると思います。例えば、「対象のメソッドが、現在の環境やプラットフォームの情報にアクセスしているかどうかを知りたいので、クラス Environment のいずれかのメソッドの呼び出しを検出したい」というようなことが考えられますね。これを実現するために、Prig では間接スタブのデフォルトの振る舞いを変更する機能をサポートしています。今回はこの機能を解説していきましょう。


以下の記事、ライブラリを使用/参考にさせていただいています。この場を借りてお礼申し上げます m(_ _)m
Muhammad Shujaat Siddiqi Prefer 32-Bit with Any CPU Platform Target - Visual Studio 2012 Enhancements
何かのときにすっと出したい、プログラミングに関する法則・原則一覧 by @hiroki_daichi on @Qiita
OpenTouryoProject/OpenTouryo - GitHub
Code Generation in a Build Process
Microsoft.Fakes stub interface fails to be found - Stack Overflow
Microsoft Fakes: Trying to shim a class but dependencies are still there - Stack Overflow
c# - How do you call a constructor via an expression tree on an existing object? - Stack Overflow
Why did we build
rspec の書き方がわからない"" - Togetterまとめ
Myron Marston » Notable Changes in RSpec 3





目次

デフォルトの振る舞い
例として、以下のような「古き良き時代の」コードに対して、仕様の変更が発生した、ということを想像してみてください - もちろん、テストコードはありませんね (´・ω・`)

NotifyStartJob は、最初に、あるジョブを実行するための前提条件を検証し、全ての条件が満たされていれば、ジョブに引き渡すパラメータファイルを生成します。goto 文を使って、共通のエラー処理に飛ばす手法は、C 言語が主流だった時代によく見られたものですが、例外による通知が標準になった現在でも、そのエラーが本当の例外でなく単に業務的なエラーだったり、パフォーマンスの問題があったりすれば、まだ利用されることがあるかもしれません。

ちょっと簡単ではないということを感じたあなたは、テストコードを書くことにしました。まずは、古くからあるモックフレームワークとちょっとの修正で可能な範囲で、その振る舞いを囲うことにします。プロダクトコードを見回すと、CommunicationContext は構造体である必要はなさそう。クラスに変更し、メンバーを virtual にすることにしました:

メンバーが static であることも止めたいですが、それはできません。なぜなら、他の多くのメンバから参照されてしまっているためです。仕方がないので、ここで、Prig を使い間接スタブを作成することにします。Package Manager Console で、以下のコマンドを実行してスタブ設定を作成し・・・:

以下のコマンドで、UpdateJobParameterFile の設定をクリップボードにコピーし、スタブ設定(例えば、GofUntestable.v4.0.30319.v1.0.0.0.prig)に追加します:


上記の準備によって、全てのテストが書けるようになります。例えば、以下のようなケースが書けると思います:

ところで、今回の仕様変更は何だったかというと、「ライセンスによる検証を削除する」というものでした。具体的には、「VerifyProductLicense はもう呼ばれない」ということを実装すれば良いことになります。以下のようにテストの Assert の一部を書き換え、テストが失敗することを確認します:

あとは、テストが通るようにプロダクトコードを変更するだけですね!あなたは安心して、JobManager を以下のように書き換え、テストが成功することを確認します。簡単な仕事でしたね?

・・・アイヤー、これはヒドイ。問題に気づきましたか?これでは常に goto fail; へ行ってしまい、ジョブに渡すパラメータファイルが常に作成されてしまいます!加えて、残念なことに、JobManager は err を code として、UpdateJobParameterFile に 設定していますので、最悪ジョブが常に実行されることになるでしょう。今年 2 月にあった Apple 史上最悪のセキュリティバグが思い出されますね。

このような問題を防止するには、意図しないメソッドが呼び出されたら例外を投げるようにします。この例では、fail ラベルで、問題があった環境の情報をログに書き込む処理があり、Environment の各プロパティを参照しているようです。従って、それらが呼び出された時に例外をスローするのが良いでしょう。Environment は mscorlib に属すクラスで、ほとんどのメンバが static です。この場合、Prig を使って間接スタブを作成する以外に、選択の余地はありませんね:

上のコマンドを実行すると、mscorlib の間接スタブ設定を作成することができます。そうしましたら、Environment の public static なメンバーの間接スタブを作成しましょう(以下のコマンドの結果を mscorlib.v4.0.30319.v4.0.0.0.prig に貼り付けます):

さて、これで Environment の public static なメンバーに対して、一度にデフォルトの振る舞いを変更できるようになりました。テストコードに、以下の変更を加えます:

使用しているモックフレームワークによっては、既に予約されているメンバーがあるため、Environment のいくつかのメンバーを除外することがちょっとメンドクサイ(Moq のケースだと、上記の通り、Environment.CurrentManagedThreadId や Environment.OSVersion がそれに当たります)。ですが、これで意図しないメソッドの呼び出しを監視することができるようになりました。NotifyStartJob に対する上記の修正では、もはやテストが通らないことがわかると思います。これで本当に安全になったわけですね!

ちなみにこの機能、テストケースを書く時、モックのされ具合を確認することや、複雑な条件下にある外部アクセスから守るガードとしても利用ができます。また、IndirectionBehaviors.DefaultValue を設定すれば、デフォルト値を返すようなデフォルトの振る舞いに変更することもできます。レガシーコードにおいては、1 つのメソッドで何度も何度も void Foo() のようなシグネチャのメソッドが呼び出されている状況(中でメンバ変数 or グローバル変数ガシガシ変えてる!!!)も少なくないでしょう。しかし、テスト中のもの以外を何もしない振る舞いに設定すれば、簡単に観点を絞り込むことができるようになるはずです。



2014年11月19日水曜日

移行サンプル:Microsoft Fakes による HttpWebRequest のモック化 - from "Prig: Open Source Alternative to Microsoft Fakes" Wiki -

まとまってきたドキュメントを日本語の記事にもしておくよシリーズ第 3 段!(元ネタ:Prigwiki より、MIGRATION: Mocking HttpWebRequest by Microsoft Fakes。同シリーズの他記事:1 2

今回は、Microsoft Fakes から Prig への移行サンプルを解説させていただきますね。Fakes の解説ドキュメント「Better Unit Testing with Microsoft Fakes」の章「Migrating from commercial and open source frameworks」に載せられているマイグレーションの説明を、例として挙げています。


以下の記事、ライブラリを使用/参考にさせていただいています。この場を借りてお礼申し上げます m(_ _)m
An Introduction To RSpec | Treehouse Blog
Ruby - refinementsについてグダグダ - Qiita
Medihack » Blog Archive » Intend to extend (metaprogramming in Ruby)
c# - How does WCF deserialization instantiate objects without calling a constructor - Stack Overflow
Runtime method hooking in Mono - Stack Overflow
.NET CLR Injection: Modify IL Code during Run-time - CodeProject
CLR Injection: Runtime Method Replacer - CodeProject
Moles: Tool-Assisted Environment Isolation with Closures - Microsoft Research





目次

移行サンプル:Microsoft Fakes による HttpWebRequest のモック化
テスト対象はこんな感じ(警告が発生していたため、若干修正してあります):

個人的に、副作用への入力を検証していなかったり、テストメソッド名に期待値が含まれていなかったりで、元の例はいただけません。それはさておき、とりあえずビルドが成功するぐらいには Prig へ移行してみましょう。なお、プロジェクトの Assembly 参照設定は Moles の移行サンプルと同様ですので、詳細はそちらをご参照ください。

Fakes の「Shim」と呼ばれるクラスは、Prig の「Indirection Stub」に当たります。命名規則によって、「Shim」として利用されているクラスは、HttpWebRequest、WebRequest そして HttpWebResponse ということがわかります。これらのクラスは全てアセンブリ System に属していますので、以下のコマンドで間接設定を追加してください:

間接設定 System.v4.0.30319.v4.0.0.0.prig が追加されたら、以下のコマンドを実行することによって作成される結果を貼り付けます:

? { !$_.IsAbstract } は、実装を持っていないメソッドを除外するフィルター、$_.DeclaringType -eq $_.ReflectedType はベースメソッドをオーバーライドするメソッドを除外するフィルターです。説明のために非常にざっくりとしたフィルターを掛けていますが、厳密なフィルターで最小限の設定を作成することをオススメします。広範囲に影響が出てしまうため、必要以上のメソッドを交換可能にしておくことは良いことではありません。

貼り付けたスタブ設定に対してビルドが正常に終了したら、こんな感じでテストが書けると思います:

ところで、この「Migrating from commercial and open source frameworks」、Fakes は、モックオブジェクトとしての機能を持っていませんので、Moq はそのまま使ったほうが簡単になったんじゃないかなと思うんですが・・・うーむ (-_-;)




付録
個人的にいただけなかった部分を Moq によって修正した例です:




さあ、次!次!
実際のところ、現状で Fakes を導入できている幸運な方は、そのままお使いいただければ良いと思います (´・_・`)

・・・一応機能的な利点を挙げるとすれば、Prig は、Fakes には無い、構造体のコンストラクト時差し替えや、サードパーティ製プロファイリングツールとの連携既存ライブラリにある、シグネチャに非公開な型を持つメソッドの入れ替えをサポートしていますが、まあ些細なことでしょう。
どちらかと言うと、OSS であるが故に、一部のニンゲンは Premium 使えるんだけど、他は Professional なんだよ?、とか CI 環境にまで Premium 以上の Visual Studio 入れなあかんの?、とか、テストだけじゃなく、例えば何か動的に処理を入れ替える仕組みを一時的に入れて開発効率を上げるみたいな、色んなことに使いたいんだけど?とか、そもそもどういう仕組みで動いてるの?とかの状況の方には、ご提案できるやもしれません・・・が、特殊なケースでしょうね。

まあ、本来はテスト向けのツールとして始めたわけじゃなかったですから・・・(震え声)

この辺は一段落したら追々考えるとして、とりあえず、次、行ってみよう! (・∀・)



2014年11月18日火曜日

移行サンプル:Microsoft Research Moles による非同期パターンのモック化 - from "Prig: Open Source Alternative to Microsoft Fakes" Wiki -

まとまってきたドキュメントを日本語の記事にもしておくよシリーズ第 2 段!(元ネタ:Prigwiki より、MIGRATION: Mocking Asynchronous Pattern by Microsoft Research Moles。同シリーズの他記事:1

今回は、『neue cc - Rx + MolesによるC#での次世代非同期モックテスト考察』で解説されているような、イベントベースの非同期パターンを採用するクラスに対して Microsoft Research Moles でモック化するサンプルを Prig(と Moq)に移行してみましょう。前述のページをキーワード「ShowGoogle」で検索すると、例を見つけられると思います。


以下の記事、ライブラリを使用/参考にさせていただいています。この場を借りてお礼申し上げます m(_ _)m
James Dibble - Blog - Microsoft Fakes Part Two
Code rant: How To Add Images To A GitHub Wiki
トンネルの思い出 - 東広島市自然研究会
IronRuby.net
Can we use fakes to test AutomationElement methods
Which Isolation frameworks have you used in the past 3 months?
Battle of the mocking frameworks by @dhelper #mockingframework #softwaredevelopment
djUnit
unit testing - HOW to use MS Fakes shims with NSubstitute mocks? - Stack Overflow





目次

移行サンプル:Microsoft Research Moles による非同期パターンのモック化
プロジェクト MolesMigrationDemo に、メソッド ShowGoogle を持つ ULWebClient を作成し、そのテストプロジェクト MolesMigrationDemoTest を作成します:




MolesMigrationDemoTest に NUnit への参照を追加し、README.md に従って Prig をインストールします。あ、Moq の追加を忘れずに:


mscorlib に属す Console、System に属す WebClient、DownloadStringCompletedEventArgs のモック化を有効にする必要がありますので、以下のコマンドを実行し、間接スタブ設定を作成していきましょう:

padd -as は、Add-PrigAssembly -Assembly のエイリアスです。このコマンドの実行により、mscorlib.v4.0.30319.v4.0.0.0.prig と System.v4.0.30319.v4.0.0.0.prig がテストプロジェクトに追加されます:



次に、以下のコマンドを実行します。これは、Console のための間接スタブ設定をクリップボードにコピーするという意味ですね。で、mscorlib.v4.0.30319.v4.0.0.0.prig に貼り付けます:


ちなみに、エイリアスについて説明しておくと、pfind は Find-IndirectionTarget、pget は Get-IndirectionStubSetting に当たります。貼り付けた結果はこんな感じ:



同様に、WebClient と DownloadStringCompletedEventArgs の設定を作成します。Get-IndirectionStubSetting は MethodBase の配列を渡しさえすれば、良い感じにスタブ設定を作成してくれますので、PowerShell で、標準のリフレクション API から取得した結果を使い、フィルタリングしても何ら問題はありません:

そうしたら、次のように System.v4.0.30319.v4.0.0.0.prig へ結果を貼り付けます:



さて、ビルドは通りましたか?そうであれば、間接スタブを使うことができます。以下のように、オリジナルの例から移行することができるでしょう:




さっくりとまとめ
去年の時点では、まだ私の観測範囲でもバリバリ使われてた感じの Moles。 これのインパクトがあったせいか、.NET で static/final/sealed/拡張メソッド入れ替え可能な Mocking フレームワーク、無償なヤツって無いの?、みたいな話題は、QA サイトに定期的に上がる感じ。残念ながら、今のところ、あまり進展は無い感じですね。

V1.0.0 にもなったことですし、今後は私のほうでも、そのような話題を見つけたら、積極的にアプローチしてみたいと思います。人ばs…改善のアイディアも、頂けるかもしれませんしね。

Prig. It is my weekend project but it is expressed an open source alternative to Microsoft Fakes!! ;)



2014年11月17日月曜日

クイックツアー変更分と既存 Mocking ライブラリとの連携 - from "Prig: Open Source Alternative to Microsoft Fakes" Wiki -

リリースです!!

  プロジェクトページ:Prig Open Source Alternative to Microsoft Fakes By @urasandesu
  NuGet:NuGet Gallery | Prig Open Source Alternative to Microsoft Fakes 1.0.0

テストやサンプルの追加が思ったよりうまく進み、また、課題だった部分が全て解決できたことや、ドキュメントがだいぶまとまってきたこともあり、予定より少し早めることができました。
リリースに際し、これまで日本語になっていなかったドキュメントは、この記事を含め順次日本語化していこうと思います。拙い英語なので、もし日本語記事を読んでいただいた後でドキュメントを読んで「あ、そういうことが言いたいんだったら、この言い回しにしたほうが良いよ」のようなことがありましたら、是非 @urasandesu にリプをしていただくなり、Issues に積んでいただくなりしていただければありがたいです。これから全 9 回を予定していますが、よろしければ最後までお付き合いくださいませ。

さて、導入手順であるクイックツアーがまた変わりましたので(だいぶ簡単になりましたよ!)、そこから解説していきましょう。加えて、今回は伝統的なモッキングフレームワークとの連携を。ちなみに Prig は、伝統的なモッキングフレームワークの機能をサポートしていません。OSS で既に必要な機能を持つライブラリが存在するのであれば、それらを使えば良いだけですからね。ただ、そのようなライブラリと連携できないことには話になりません。代表的なライブラリとして、MoqNSubstituteRhino MocksFakeItEasy を例にとり、それらと Prig を連携して利用する方法を解説していきます。

それでは、行ってみましょう!


以下の記事、ライブラリを使用/参考にさせていただいています。この場を借りてお礼申し上げます m(_ _)m
Getting Started with Unit Testing Part 3 | Visual Studio Toolbox | Channel 9
GenericParameterAttributes Enumeration (System.Reflection)
How can I fake OLEDB.OleDBDataAdapter to shim OleDBDataAdapter.Fill(dataSet) to shim results for unit testing using NUnit - Stack Overflow
c# - Can I Change Default Behavior For All Shims In A Test - Stack Overflow
IMetaDataImport2::GetVersionString Method
Obtaining List of Assemblies present in GAC
How should I create or upload a 32-bit and 64-bit NuGet package? - Stack Overflow
visual studio - Can NuGet distribute a COM dll? - Stack Overflow
Project Template in Visual Studio 2012 - CodeProject
Preferred way to mock/stub a system resource like System.Threading.Mutex - Stack Overflow





目次

クイックツアー(変更分)
NuGet への対応や、前回挙げていた懸念事項が全て解けたことを経て、導入手順はまたかなり変わりました。毎回の登場で恐縮ですが、「テストしにくい副作用を直接参照している処理」を例に見ていきます:

手順としては以下のような感じ:
Step 1: NuGet からインストール
Step 2: スタブ設定の追加
Step 3: スタブ設定の修正
Step 4: テストの作成
Step 5: テストの実行
Final Step: リファクタリングしてキレイに!
「手順増えてるじゃないですかやだー」と思われるかもしれませんが、1 つ 1 つの手順が軽くなっているので大丈夫です (^-^; では、実際にやってみましょう!


Step 1: NuGet からインストール
Visual Studio 2013(Express for Windows Desktop 以上)を管理者権限で実行し、テストを追加します(例えば、ConsoleApplicationTest)。そして、以下のコマンドを Package Manager Console で実行します:

※注:ほとんどの場合、インストールは上手く行きます。が、Visual Studio のインストール直後だと上手く行かないことがあるようです。こちらの Issue にあるコメントもご参照ください


Step 2: スタブ設定の追加
以下のコマンドを Package Manager Console で実行します:

このコマンドは、テストのための間接スタブ設定を作成する、という意味です。mscorlib を指定しているのは、DateTime.Now が mscorlib に属しているからですね。コマンド実行後、外部からプロジェクトの変更があったけどどうします?という旨の確認メッセージが表示されますので、プロジェクトをリロードしてください。


Step 3: スタブ設定の修正
プロジェクトに設定ファイル <assembly name>.<runtime version>.v<assembly version>.prig を見つけられると思います(この場合だと、mscorlib.v4.0.30319.v4.0.0.0.prig ですね)。設定ファイルをコメントに従い修正したら、全てのプロジェクトをビルドします:



Step 4: テストの作成
テストコードにおいては、スタブの使用と偽の情報を返す Test Double への入れ替えを通じ、テスト可能になります:



Step 5: テストの実行
本来、プロファイラベースのモックツールを有効にするには、環境変数を弄る必要があります。そのため、そのようなライブラリ(Microsoft Fakes/Typemock Isolator/Telerik JustMock)は、要件を満たすための小さなランナーを提供しますが、それは Prig でも真となります。prig.exe を使い、以下の通りテストを実行します(引き続き Package Manager Console で)。



Final Step: リファクタリングしてキレイに!
テストができてしまえば、リファクタリングに躊躇はなくなりますね!例えば、以下のようにリファクタリングできるでしょう:

こんな感じで、Prig はテストしにくいライブラリに依存するようなコードをキレイにするのをサポートしてくれます。開発がまた楽しくなること請け合いですよ!


PowerShell モジュールによるサポートがだいぶ手厚くなったおかげで、手書きで *.csproj を触ったり、コマンドを組み立てたりする必要はなくなりました。ただ、その分環境に依存しやすくなっていますので、一長一短かなとも思います。あとはパフォーマンスですね。懸念事項が片付いた今なら、現状行っている DLL 解析⇒ソースコード生成⇒*.csproj 生成⇒MSBuild でソースコードをビルドし、スタブ Assembly を生成 という冗長な処理を、DLL 解析⇒スタブ Assembly を生成、にまで最適化できるはず。ただ、これには、アンマネージ API をラップしている Swathe を、だいぶ整理する必要があるため、次のメジャーバージョンアップ時を目指して、ぼちぼちやっていく予定です。他にも、Code Digger や、Pex のような、テストコード自動生成機能の搭載や、Telerik JustMock がやっているようなネイティブ API の入れ替え、導入手順のさらなる簡易化などもチャレンジしていきたいところですね。





既存 Mocking ライブラリとの連携
次は既存 Mocking ライブラリとの連携です。以下のクラスのテストについて考えてみましょう:

たぶん、「ValueWithRandomAdded は、PropertyChanged イベントをその名前で発火するべき」や「ValueWithRandomAdded は、渡された値 + Random.Next() を保持するべき」のようなテストをしたくなると思います。後者について、MoqNSubstituteRhino MocksFakeItEasy を使ってテストをする連携サンプルを紹介します。

共通の前準備として、Random.Next() のための間接スタブ設定を追加します。Prig をインストールし、各テストプロジェクトで以下のコマンドを実行してください:

スタブ設定ファイルが追加されたら、クラス Random のためのスタブ設定をクリップボードにコピーするため、以下のコマンドを実行します:

そして、それをスタブ設定ファイル mscorlib.v4.0.30319.v4.0.0.0.prig に貼り付けます。それでは、それぞれのモッキングフレームワークとの連携を見ていきましょう!



Moq
Moq の連携サンプルです。



NSubstitute
NSubstitute の連携サンプルです。



Rhino Mocks
Rhino Mocks の連携サンプルです。



FakeItEasy
FakeItEasy の連携サンプルです。

え?「全部同じようなサンプルに見える」ですって?はい、その通りです。重要なことはただ一つ、「デリゲートのためのモックを作成することを意識する」だけですから。そのような機能持っているものの中から、お好きなものをお選びください!(>ω・)




終わりに
つい先日、マイクロソフトから .NET Framework のオープンソース化や、フル機能無料版の Visual Studio の提供.NET Server Framework の Linux/MacOS X 向けディストリビューションの展開の発表があり、大きなニュースになりましたね。
ただ、オープンソース化された .NET Framework コアを見ると、本当のコア部分(ランタイムホストや JIT、プロファイラ内でも動くような制限のないメタデータ操作、リソースの検索・・・etc。いわゆる、昔、SSCLI として公開された範囲ですね)は含まれていないですし(.NET Core Runtime について、"We’re currently figuring out the plan for open sourcing the runtime. Stay tuned!"と言っているので何かしら提供する気はありそうなのですが・・・)、無償化された Visual Studio Community 2013 はビジネスユースが限定されていたり、その機能は Professional 止まりだったりと、押さえるところは押さえてるっていう印象です。まあ、経営戦略上、必要なものを公開・無償化したというだけと言えばだけなのかもしれません。

私がずっと追っている自動ユニットテスト関連の Visual Studio 拡張の中でも、Microsoft Fakes は、Community エディションには搭載されませんでした。Fakes は、当初から全エディションに搭載して!という声が上がっているにも関わらず、Premium 以上の機能のままですので、こちらも当たり前と言えば当たり前。また、その前身の Moles が動く Visual Studio 2010 のメインストリームサポートが、来年の夏ごろ終わることを考えると、このタイミングで無償化されなかったということは、今後無償化されるとしても良いタイミングになるとは言えない気がします。

そんなこんなで、私が 5 年前から作っていたこのライブラリも、Microsoft Fakes のオープンソース代替実装として、収まるところに収まってしまいました。いや正直、開発し始めた当時、こんな大仰なことを謳えるようになるとは思ってもみなかったですががが… (∩´﹏`∩) 。

まだまだ至らない点があるかと思いますが、これを機に、Prig、.NET 開発のお供として、末永くお付き合いいただければ幸いでございます。