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 を作成します:



using System;
using System.Net;
namespace MolesMigrationDemo
{
public class ULWebClient
{
public static void ShowGoogle()
{
var client = new WebClient();
client.DownloadStringCompleted += (sender, e) =>
{
Console.WriteLine(e.Result);
};
client.DownloadStringAsync(new Uri("http://google.co.jp/"));
}
}
}
view raw 02_01.cs hosted with ❤ by GitHub

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


mscorlib に属す Console、System に属す WebClient、DownloadStringCompletedEventArgs のモック化を有効にする必要がありますので、以下のコマンドを実行し、間接スタブ設定を作成していきましょう:
PM> padd -as "mscorlib, Version=4.0.0.0"
PM> padd -as "System, Version=4.0.0.0"
view raw 02_02.ps1 hosted with ❤ by GitHub

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 に貼り付けます:

PM> pfind ([System.Console]) 'WriteLine\(System.String\)' | pget | clip
view raw 02_03.ps1 hosted with ❤ by GitHub

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



同様に、WebClient と DownloadStringCompletedEventArgs の設定を作成します。Get-IndirectionStubSetting は MethodBase の配列を渡しさえすれば、良い感じにスタブ設定を作成してくれますので、PowerShell で、標準のリフレクション API から取得した結果を使い、フィルタリングしても何ら問題はありません:
PM> $targets = [System.Net.WebClient].GetMembers([System.Reflection.BindingFlags]'Public, Instance') | ? { $_ -is [System.Reflection.MethodBase] } | ? { $_.ToString() -match 'DownloadString' }
PM> $targets += [System.Net.DownloadStringCompletedEventArgs].GetMembers([System.Reflection.BindingFlags]'Public, Instance') | ? { $_ -is [System.Reflection.MethodBase] } | ? { $_.ToString() -match 'Result' }
PM> $targets | pget | clip
view raw 02_04.ps1 hosted with ❤ by GitHub

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



さて、ビルドは通りましたか?そうであれば、間接スタブを使うことができます。以下のように、オリジナルの例から移行することができるでしょう:
using MolesMigrationDemo;
using Moq;
using NUnit.Framework;
using System.Net;
using System.Net.Prig;
using System.Prig;
using Urasandesu.Prig.Framework;
namespace MolesMigrationDemoTest
{
[TestFixture]
public class ULWebClientTest
{
[Test]
public void ShowGoogle_should_write_response_from_google_to_standard_output()
{
// Prig には、HostType("Moles") のような属性はありません。 using (new IndirectionsContext()) を代わりに使ってください。
using (new IndirectionsContext())
{
// Arrange
var handler = default(DownloadStringCompletedEventHandler);
handler = (sender, e) => { };
// 全てのインスタンスのメンバーをモック化する Moles の AllInstances のような機能はありません。デフォルトがそのような機能であるためです。
PWebClient.AddDownloadStringCompletedDownloadStringCompletedEventHandler().Body = (@this, value) => handler += value;
PWebClient.RemoveDownloadStringCompletedDownloadStringCompletedEventHandler().Body = (@this, value) => handler -= value;
PWebClient.DownloadStringAsyncUri().Body = (@this, address) =>
{
// 特定のインスタンスに対してモック化を行いたい場合は、PProxy で始まるスタブを使います。
var e = new PProxyDownloadStringCompletedEventArgs();
e.ResultGet().Body = @this_ => "google!modoki";
handler(@this, e);
};
var mockWriteLine = new Mock<IndirectionAction<string>>();
mockWriteLine.Setup(_ => _(It.IsAny<string>()));
PConsole.WriteLineString().Body = mockWriteLine.Object;
// Act
ULWebClient.ShowGoogle();
// Assert
mockWriteLine.Verify(_ => _("google!modoki"), Times.Once());
}
}
}
}
view raw 02_05.cs hosted with ❤ by GitHub




さっくりとまとめ
去年の時点では、まだ私の観測範囲でもバリバリ使われてた感じの 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!! ;)



0 件のコメント:

コメントを投稿