2014年12月1日月曜日

移行サンプル:Telerik JustMock によるモック化② シールされたクラスのモック化 - from "Prig: Open Source Alternative to Microsoft Fakes" Wiki -

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

3 回に渡る JustMock の公式ドキュメントにあるサンプルを実装するシリーズ、Part 2 となります。今回は、「Sealed Mocking samples」を Prig に移行してみましょう。


以下の記事、ライブラリを使用/参考にさせていただいています。この場を借りてお礼申し上げます m(_ _)m
Unity を使って AOP - present
How do microsoft fakes' shims actually work internally? - Stack Overflow
c# - Good and free unit-testing alternatives to Telerik's JustMock - Software Recommendations Stack Exchange
Unable to create Fakes for Google APIs - Stack Overflow
Covering basics of unit testing with Typemock - .NET Unit Testing Tips
The Difference Between Unit Tests and Integration Tests - Typemock Isolator
Typemock Isolator Quick Start -
Home - Run Jekyll on Windows
Setup Jekyll on Windows - Yi Zeng
OctopressをWindows7にインストールしてみたメモ by @pon_zu on @Qiita





目次

準備
このサンプルでは、シリーズということもあり、1 つのソリューションに複数のプロジェクトを追加するという構成を採っています。前回のサンプルと同様、Package Manager Console と PowerShell を使って説明を続けたいと思います。各使用コマンドは前回のサンプルで解説していますので、詳細はそちらもご覧ください。

まずは、間接スタブ設定を作成しましょう:
PM> dir
Directory: C:\Users\Akira\Documents\Visual Studio 2013\Projects\JustMockMigrationDemo
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 2014/09/17 19:34 FinalMockingMigration
d---- 2014/09/23 16:55 FinalMockingMigrationTest
d---- 2014/09/25 6:13 packages
d---- 2014/09/16 20:32 SealedMockingMigration
d---- 2014/09/16 20:34 SealedMockingMigrationTest
d---- 2014/09/16 20:37 StaticMockingMigration
d---- 2014/09/21 11:35 StaticMockingMigrationTest
-a--- 2014/09/16 6:31 3665 JustMockMigrationDemo.sln
PM> cd .\SealedMockingMigration\bin\Debug
PM> dir
Directory: C:\Users\Akira\Documents\Visual Studio 2013\Projects\JustMockMigrationDemo\SealedMockingMigration\bin\Debug
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2014/09/25 6:18 5120 SealedMockingMigration.exe
-a--- 2014/09/16 6:31 189 SealedMockingMigration.exe.config
-a--- 2014/09/25 6:18 13824 SealedMockingMigration.pdb
PM> padd -af (dir .\SealedMockingMigration.exe).FullName
PM>
view raw 06_01.ps1 hosted with ❤ by GitHub

あー・・・「やっべ!Default project: にテストプロジェクト設定してねえ!変なとこに設定が追加された!!!!」って方。

お気の毒さまですが、Prig はそれを削除するコマンドをサポートしていません(PreBuildEvent 内の解析ェ・・・)。恐縮ですが、手動で *.csproj を元に戻す必要があります。以下のイメージのように、\.prig" にマッチするタグ Reference、None、PreBuildEvent の全てを削除してください:









Git のようなバージョン管理システム下で作業することを強くお勧めしておきます (^q^)

次は、PowerShell(コンソール)による対象メソッドの絞り込みです。慣れれば一気にできるでしょう:
PS> $pwd
Path
----
C:\Users\Akira\Documents\Visual Studio 2013\Projects\JustMockMigrationDemo\SealedMockingMigration\bin\Debug
PS> powershell
Windows PowerShell
Copyright (C) 2013 Microsoft Corporation. All rights reserved.
PS> ipmo "C:\Users\Akira\Documents\Visual Studio 2013\Projects\JustMockMigrationDemo\packages\Prig.1.0.0\tools\Urasandesu.Prig"
PS> dir
Directory: C:\Users\Akira\Documents\Visual Studio 2013\Projects\JustMockMigrationDemo\SealedMockingMigration\bin\Debug
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2014/09/27 6:45 5120 SealedMockingMigration.exe
-a--- 2014/09/16 6:31 189 SealedMockingMigration.exe.config
-a--- 2014/09/27 6:45 17920 SealedMockingMigration.pdb
PS> $asmInfo = [System.Reflection.Assembly]::LoadFrom((dir .\SealedMockingMigration.exe).FullName)
PS> $asmInfo.GetTypes()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False FooSealed System.Object
True False FooSealedInternal System.Object
True False IFoo
True False Foo System.Object
False False Program System.Object
PS> $asmInfo.GetTypes() | pfind
Method
------
Int32 Echo(Int32)
Void .ctor()
Int32 Echo(Int32)
Void .ctor()
Void Execute()
Void SealedMockingMigration.IFoo.Execute(Int32)
Void .ctor()
Void Main(System.String[])
Void .ctor()
PS> $asmInfo.GetTypes() | pfind | pget | clip
PS> exit
PS>
view raw 06_02.ps1 hosted with ❤ by GitHub

今回は、Moles の例以降、表に出てこなかったコマンド pfind(Find-IndirectionTarget)を使っています。実はこのコマンド、前回までのサンプルで、標準リフレクション API によって掛けていたざっくりとしたフィルタを、既に含んでいます。なので、上記のように手順の簡易化ができるようになるんですね。そうしたら、Visual Studio に戻り、前回と同様 SealedMockingMigration.v4.0.30319.v1.0.0.0.prig に貼り付けます。ビルドは通りましたか?さあ、実際の移行をしてみましょう!





Assert Final Method Call on a Sealed Class
シールされたクラスの final メソッドを置き換えてみましょう:
[Test]
public void Prig_should_assert_final_method_call_on_a_sealed_class()
{
using (new IndirectionsContext())
{
// Arrange
PFooSealed.EchoInt32().Body = (@this, arg1) => 10;
// Act
var actual = new FooSealed().Echo(1);
// Assert
Assert.AreEqual(10, actual);
}
}
view raw 06_03.cs hosted with ❤ by GitHub

特定のインスタンスだけの置き換えるのでない時は、PProxy<original class name> を使うより、P<original class name> を使うほうが簡単かも。





Create Mock for Sealed Class with Internal Constructor
ところで、入れ替える型のコンストラクタが非 public だとどうなるのか、心配になったりします?:
[Test]
public void Prig_should_create_mock_for_a_sealed_class_with_internal_constructor()
{
using (new IndirectionsContext())
{
// Arrange
var fooProxy = new PProxyFooSealedInternal();
fooProxy.EchoInt32().Body = (@this, arg1) => 10;
var foo = (FooSealedInternal)fooProxy;
// Act
var actual = foo.Echo(1);
// Assert
Assert.AreEqual(10, actual);
}
}
view raw 06_04.cs hosted with ❤ by GitHub

はい!何も問題ありませんね!





Create Mock for Sealed Class with Interface
これはインターフェイスを使った振る舞いの例です。まずは直呼び出し:
[Test]
public void Prig_should_assert_call_on_void()
{
using (new IndirectionsContext())
{
// Arrange
var called = false;
PFoo.Execute().Body = @this => called = true;
// Act
new Foo().Execute();
// Assert
Assert.IsTrue(called);
}
}
view raw 06_05.cs hosted with ❤ by GitHub

次に、インターフェイスを通じた呼び出し:
[Test]
public void Prig_should_assert_call_on_void_through_an_interface()
{
using (new IndirectionsContext())
{
// Arrange
var called = false;
PFoo.Execute().Body = @this => called = true;
var foo = new Foo();
// Act
var iFoo = (IFoo)foo;
iFoo.Execute();
// Assert
Assert.IsTrue(called);
}
}
view raw 06_06.cs hosted with ❤ by GitHub

加えて、明示的に実装されたインターフェイスのケースです。これについては、JustMock はサンプルを準備していないようですね。なので、一応念のため説明させていただきます:
[Test]
public void Prig_should_assert_call_on_void_through_an_explict_implemented_interface()
{
using (new IndirectionsContext())
{
// Arrange
var called = false;
PFoo.SealedMockingMigrationIFooExecuteInt32().Body = (@this, arg1) => called = true;
var foo = new Foo();
// Act
var iFoo = (IFoo)foo;
iFoo.Execute(1);
// Assert
Assert.IsTrue(called);
}
}
view raw 06_07.cs hosted with ❤ by GitHub

明示的に実装されたインターフェースを入れ替える時は、間接スタブが特殊な名前になることだけに気を付ければ大丈夫です。通常の名前は、単に <メソッドの間接スタブ名> ですが、この場合の名前は、<名前空間> + <インターフェイスの間接スタブ名> + <メソッドの間接スタブ名> となります。



0 件のコメント:

コメントを投稿