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
目次
- 準備
- Static Constructor Mocking
- General Static Method Mocking
- Mocking Static Property Get
- Mocking Static Property Set
- Mocking Internal Static Call
- Mocking Static Class
- Mocking Current HttpContext
- Mocking Extension Methods
準備
このサンプルでは、シリーズということもあり、1 つのソリューションに複数のプロジェクトを追加するという構成を採っています(前回、前々回の記事もご参照くださいませ)。これまでのサンプルと同様、Package Manager Console と PowerShell を使って説明を続けたいと思います。各使用コマンドは以前のサンプルで解説していますので、詳細はそちらもご覧ください。
さて、間接スタブ設定を作成しましょう。Package Manager Console を開き、Default project: をテストプロジェクトに変更します:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | |
次に、Assembly を解析します。PowerShell(コンソール)を開き、以下のコマンドで情報を取得します:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | |
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 という名前になります:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[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); | |
} | |
} |
General Static Method Mocking
一般的な静的メソッドのモック化です。んー、これは Moq と連携したほうがわかりやすいでしょうね:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[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()); | |
} | |
} |
ところで、個人的には ExpectedException より Assert.Throws のほうが好きだったり。ExpectedException を使うケースだと、意図しない場所で例外が発生しても(例えば、上記の例だと、Foo.Execute(10) が例外をスロー時)、テストは成功してしまいますからね。
Mocking Static Property Get
静的プロパティの getter を入れ替えます。何度か説明してきているように思いますが・・・一応紹介しておきましょう (^_^;)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[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); | |
} | |
} |
Mocking Static Property Set
静的プロパティの setter を入れ替えます:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[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; | |
} | |
} |
検証の方法について、JustMock のサンプルとは若干違いがあります。個人的には、MockBehavior.Strict を指定すれば、条件によってメソッドが呼び出されているかどうかを再度検証する必要はないとは思いますね。条件を満たさないメソッドの呼び出しがあれば、自動的に例外がスローされますので。
Mocking Internal Static Call
internal な静的メソッドを入れ替える例です。コメントに残すだけでなく、例外がスローされないことも検証すべきでしょう:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Test] | |
public void Prig_should_fake_internal_static_call() | |
{ | |
using (new IndirectionsContext()) | |
{ | |
// Arrange | |
PFooInternal.DoIt().Body = () => { }; | |
// Act, Assert | |
Assert.DoesNotThrow(() => FooInternal.DoIt()); | |
} | |
} |
Mocking Static Class
静的クラスのメソッドを入れ替えるサンプルです。説明すべきことはあまりないですね (^-^;
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Test] | |
public void Prig_should_mock_static_class() | |
{ | |
using (new IndirectionsContext()) | |
{ | |
// Arrange | |
PFooStatic.Do().Body = () => { }; | |
// Act, Assert | |
Assert.DoesNotThrow(() => FooStatic.Do()); | |
} | |
} |
Mocking Current HttpContext
現在の HTTP コンテキストを入れ替えるサンプルです。本来であれば、元の処理は HTTP リクエスト中にのみ有効なのですが、もはや制限はありません。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[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); | |
} | |
} |
Mocking Extension Methods
拡張メソッドの入れ替えです。結局のところ、拡張メソッドは静的メソッドですので、前までのサンプルと同じように入れ替えることができます:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[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); | |
} | |
} |
0 件のコメント:
コメントを投稿