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
目次
- 準備
- Assert Final Method Call on a Sealed Class
- Create Mock for Sealed Class with Internal Constructor
- Create Mock for Sealed Class with Interface
準備
このサンプルでは、シリーズということもあり、1 つのソリューションに複数のプロジェクトを追加するという構成を採っています。前回のサンプルと同様、Package Manager Console と 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
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> | |
あー・・・「やっべ!Default project: にテストプロジェクト設定してねえ!変なとこに設定が追加された!!!!」って方。
お気の毒さまですが、Prig はそれを削除するコマンドをサポートしていません(PreBuildEvent 内の解析ェ・・・)。恐縮ですが、手動で *.csproj を元に戻す必要があります。以下のイメージのように、\.prig" にマッチするタグ Reference、None、PreBuildEvent の全てを削除してください:



Git のようなバージョン管理システム下で作業することを強くお勧めしておきます (^q^)
次は、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\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> | |
今回は、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 メソッドを置き換えてみましょう:
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_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); | |
} | |
} |
特定のインスタンスだけの置き換えるのでない時は、PProxy<original class name> を使うより、P<original class name> を使うほうが簡単かも。
Create Mock for Sealed Class with Internal Constructor
ところで、入れ替える型のコンストラクタが非 public だとどうなるのか、心配になったりします?:
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_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); | |
} | |
} |
はい!何も問題ありませんね!
Create Mock for Sealed Class with Interface
これはインターフェイスを使った振る舞いの例です。まずは直呼び出し:
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_call_on_void() | |
{ | |
using (new IndirectionsContext()) | |
{ | |
// Arrange | |
var called = false; | |
PFoo.Execute().Body = @this => called = true; | |
// Act | |
new Foo().Execute(); | |
// Assert | |
Assert.IsTrue(called); | |
} | |
} |
次に、インターフェイスを通じた呼び出し:
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_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); | |
} | |
} |
加えて、明示的に実装されたインターフェイスのケースです。これについては、JustMock はサンプルを準備していないようですね。なので、一応念のため説明させていただきます:
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_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); | |
} | |
} |
明示的に実装されたインターフェースを入れ替える時は、間接スタブが特殊な名前になることだけに気を付ければ大丈夫です。通常の名前は、単に <メソッドの間接スタブ名> ですが、この場合の名前は、<名前空間> + <インターフェイスの間接スタブ名> + <メソッドの間接スタブ名> となります。
0 件のコメント:
コメントを投稿