2014年12月4日木曜日

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

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

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


以下の記事、ライブラリを使用/参考にさせていただいています。この場を借りてお礼申し上げます m(_ _)m
How often are fakes assemblies generated? - Stack Overflow
Brownfield Development: Taming Legacy Code with Better Unit Testing and Microsoft Fakes
Nested Types in Generic Classes - Haibo Luo's weblog - MSDN Blogs
c# - Behavedbase in fakes - Stack Overflow
CLR Profiler - Documentation
Resize image in the wiki of github usin markdown - Stack Overflow
Behind iPhone's Critical Security Bug, a Single Bad 'Goto' WIRED
microsoft fakes only stub static property of a static class - Stack Overflow
Home Page - Code Impact - .NET Community Event
PowerShell で SIGPIPE 連鎖 - NyaRuRuが地球にいたころ
Generics and Your Profiler - David Broman's CLR Profiling API Blog - Site Home - MSDN Blogs





目次

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

さて、間接スタブ設定を作成しましょう。Package Manager Console を開き、Default project: をテストプロジェクトに変更します
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/28 8:46 packages
d---- 2014/09/27 6:45 SealedMockingMigration
d---- 2014/09/27 7:06 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 .\StaticMockingMigration\bin\Debug
PM> dir
Directory: C:\Users\Akira\Documents\Visual Studio 2013\Projects\JustMockMigrationDemo\StaticMockingMigration\bin\Debug
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2014/09/25 6:18 5120 StaticMockingMigration.exe
-a--- 2014/09/16 6:31 189 StaticMockingMigration.exe.config
-a--- 2014/09/25 6:18 15872 StaticMockingMigration.pdb
PM> padd -af (dir .\StaticMockingMigration.exe).FullName
PM> padd -as "System.Web, Version=4.0.0.0"
PM>
view raw 07_01.ps1 hosted with ❤ by GitHub

次に、Assembly を解析します。PowerShell(コンソール)を開き、以下のコマンドで情報を取得します:
PS> $pwd
Path
----
C:\Users\Akira\Documents\Visual Studio 2013\Projects\JustMockMigrationDemo\StaticMockingMigration\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\StaticMockingMigration\bin\Debug
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2014/09/28 11:51 5632 StaticMockingMigration.exe
-a--- 2014/09/16 6:31 189 StaticMockingMigration.exe.config
-a--- 2014/09/28 11:51 17920 StaticMockingMigration.pdb
PS> $asmInfo = [System.Reflection.Assembly]::LoadFrom((dir .\StaticMockingMigration.exe).FullName)
PS> $asmInfo.GetTypes()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False Foo System.Object
False False FooInternal System.Object
True False FooStatic System.Object
True False Bar System.Object
True False BarExtensions System.Object
False False Program System.Object
PS> $asmInfo.GetTypes() | pfind
Method
------
Void Submit()
Int32 Execute(Int32)
Int32 get_FooProp()
Void set_FooProp(Int32)
Void .cctor()
Void .ctor()
Void DoIt()
Void .ctor()
Void Do()
Void Execute()
Void .ctor()
Int32 Echo(StaticMockingMigration.Bar, Int32)
Void Main(System.String[])
Void .ctor()
PS> $asmInfo.GetTypes() | pfind | pget | clip # この結果については、StaticMockingMigration.v4.0.30319.v1.0.0.0.prig に貼り付けてください。
PS> $asmInfo = [System.Reflection.Assembly]::LoadWithPartialName("System.Web")
PS> $asmInfo.GetTypes() | ? { $_.Name -eq 'httpcontext' }
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False HttpContext System.Object
PS> $asmInfo.GetTypes() | ? { $_.Name -eq 'httpcontext' } | pfind -m 'get_current\b'
Method
------
System.Web.HttpContext get_Current()
PS> $asmInfo.GetTypes() | ? { $_.Name -eq 'httpcontext' } | pfind -m 'get_current\b' | pget | clip # この結果については、System.Web.v4.0.30319.v4.0.0.0.prig に貼り付けてください。
PS> exit
PS>
view raw 07_02.ps1 hosted with ❤ by GitHub

Visual Studio に戻り、各間接設定 StaticMockingMigration.v4.0.30319.v1.0.0.0.prig、System.Web.v4.0.30319.v4.0.0.0.prig に貼り付けます。ビルドは通りましたか?さあ、実際に移行してみましょう!





Static Constructor Mocking
静的コンストラクタの間接スタブは、文字通り StaticConstructor という名前になります:
[Test]
public void Prig_should_arrange_static_function()
{
using (new IndirectionsContext())
{
// Arrange
PFoo.StaticConstructor().Body = () => { };
PFoo.FooPropGet().Body = () => 0;
// Act
var actual = Foo.FooProp;
// Assert
Assert.AreEqual(0, actual);
}
}
view raw 07_03.cs hosted with ❤ by GitHub






General Static Method Mocking
一般的な静的メソッドのモック化です。んー、これは Moq と連携したほうがわかりやすいでしょうね:
[Test]
public void Prig_should_throw_when_not_arranged()
{
using (new IndirectionsContext())
{
// Arrange
PFoo.StaticConstructor().Body = () => { };
var executeMock = new Mock<IndirectionFunc<int, int>>(MockBehavior.Strict);
executeMock.Setup(_ => _(10)).Returns(10);
PFoo.ExecuteInt32().Body = executeMock.Object;
var submitMock = new Mock<IndirectionAction>(MockBehavior.Strict);
PFoo.Submit().Body = submitMock.Object;
// Act, Assert
Assert.AreEqual(10, Foo.Execute(10));
Assert.Throws<MockException>(() => Foo.Submit());
}
}
view raw 07_04.cs hosted with ❤ by GitHub

ところで、個人的には ExpectedException より Assert.Throws のほうが好きだったり。ExpectedException を使うケースだと、意図しない場所で例外が発生しても(例えば、上記の例だと、Foo.Execute(10) が例外をスロー時)、テストは成功してしまいますからね。





Mocking Static Property Get
静的プロパティの getter を入れ替えます。何度か説明してきているように思いますが・・・一応紹介しておきましょう (^_^;)
[Test]
public void Prig_should_fake_static_property_get()
{
using (new IndirectionsContext())
{
// Arrange
PFoo.StaticConstructor().Body = () => { };
var called = false;
PFoo.FooPropGet().Body = () => { called = true; return 1; };
// Act
var actual = Foo.FooProp;
// Assert
Assert.AreEqual(1, actual);
Assert.IsTrue(called);
}
}
view raw 07_05.cs hosted with ❤ by GitHub






Mocking Static Property Set
静的プロパティの setter を入れ替えます:
[Test]
public void Prig_should_fake_static_property_set()
{
using (new IndirectionsContext())
{
// Arrange
PFoo.StaticConstructor().Body = () => { };
var fooPropSetMock = new Mock<IndirectionAction<int>>(MockBehavior.Strict);
fooPropSetMock.Setup(_ => _(10));
PFoo.FooPropSetInt32().Body = fooPropSetMock.Object;
// Act, Assert
Foo.FooProp = 10;
}
}
view raw 07_06.cs hosted with ❤ by GitHub

検証の方法について、JustMock のサンプルとは若干違いがあります。個人的には、MockBehavior.Strict を指定すれば、条件によってメソッドが呼び出されているかどうかを再度検証する必要はないとは思いますね。条件を満たさないメソッドの呼び出しがあれば、自動的に例外がスローされますので。





Mocking Internal Static Call
internal な静的メソッドを入れ替える例です。コメントに残すだけでなく、例外がスローされないことも検証すべきでしょう:
[Test]
public void Prig_should_fake_internal_static_call()
{
using (new IndirectionsContext())
{
// Arrange
PFooInternal.DoIt().Body = () => { };
// Act, Assert
Assert.DoesNotThrow(() => FooInternal.DoIt());
}
}
view raw 07_07.cs hosted with ❤ by GitHub






Mocking Static Class
静的クラスのメソッドを入れ替えるサンプルです。説明すべきことはあまりないですね (^-^;
[Test]
public void Prig_should_mock_static_class()
{
using (new IndirectionsContext())
{
// Arrange
PFooStatic.Do().Body = () => { };
// Act, Assert
Assert.DoesNotThrow(() => FooStatic.Do());
}
}
view raw 07_08.cs hosted with ❤ by GitHub






Mocking Current HttpContext
現在の HTTP コンテキストを入れ替えるサンプルです。本来であれば、元の処理は HTTP リクエスト中にのみ有効なのですが、もはや制限はありません。
[Test]
public void Prig_should_assert_mocking_http_context()
{
using (new IndirectionsContext())
{
// Arrange
var called = false;
PHttpContext.CurrentGet().Body = () => { called = true; return null; };
// Act
var ret = HttpContext.Current;
// Assert
Assert.IsTrue(called);
}
}
view raw 07_09.cs hosted with ❤ by GitHub






Mocking Extension Methods
拡張メソッドの入れ替えです。結局のところ、拡張メソッドは静的メソッドですので、前までのサンプルと同じように入れ替えることができます:
[Test]
public void Prig_should_fake_extension_method()
{
using (new IndirectionsContext())
{
// Arrange
var foo = new Bar();
var echoMock = new Mock<IndirectionFunc<Bar, int, int>>();
echoMock.Setup(_ => _(foo, 10)).Returns(11);
PBarExtensions.EchoBarInt32().Body = echoMock.Object;
// Act
var actual = foo.Echo(10);
// Assert
Assert.AreEqual(11, actual);
}
}
view raw 07_10.cs hosted with ❤ by GitHub




0 件のコメント:

コメントを投稿