ほくろ-Microsoft Researchの分離フレームワーク、または単体テストをより便利にする方法

ユニットテストの調和のとれた、よく考えられたシステムは、コンポーネントの強力な接続性によって抑制されることがあります。これは、元々テストを目的としていないレガシーコードに特に当てはまります。 もちろん、リファクタリングは節約されます-しかし、リファクタリングが常に可能であるとは限りません。 単体テストの作成時に発生する問題の1つは、テストを正常に書き込むためにオーバーロードする必要がある静的メソッドまたは非仮想メソッドの使用です。 Microsoft Research-Molesのこのプロジェクトを支援してください。



まず、例を考えてみましょう(意図的に簡略化されています)-AcceptPaymentメソッドを含むPaymentsCoreクラスがあります-ユーザーからの支払いを登録します。 資金不足のために支払いができない場合、メソッドは例外をスローします。 タスクは、メソッドの機能をテストする単体テストを作成することです。 メソッドは入力に送信されます-ユーザーIDと支払い金額。 これがキャッチの場所です-転送されたIDに対応するユーザーデータは、特定のCacheManagerクラスの静的メソッドを使用して取得されます(データベースにアクセスし、オブジェクトをアプリケーションキャッシュに配置し、条件に応じてキャッシュを更新します)。 はい、アーキテクチャが完全に構築されているわけではないと主張できますが、これはレガシーコードであると想定します(CacheManagerのソースコードがまったく利用できない可能性があります)。 明らかに、キャッシュ、データベース、データの依存関係を取り除くには、モックオブジェクトが役立ちます。 ただし、最近まで、静的メソッドをオーバーライドできるモックフレームワークはTypeMock Isolator(高価な市販製品)のみでした。 Microsoft Research Molesの適用方法について見ていきます。

最初に、新しいテストプロジェクトを作成し、アプリケーションを使用してアセンブリへのリンクを追加し、AcceptPaymentメソッドの最も簡単なテストを記述します。

[TestMethod]

[ExpectedException( typeof (AmountException))]

public void AcceptPaymentOverdraftTest()

{

PaymentsApp.PaymentsCore core = new PaymentsCore();

core.AcceptPayment(1, 200);

}








IDが1のクライアントがデータベースに存在する場合、アカウントの資金が200を超えない場合、テストは実行されます-テストは多くの外部パラメーターに結び付けられ、概して、それは無用です。 必要な静的メソッドをモックし、テストに最適な環境を作成します。

Molesをダウンロードして (これはx86バージョンです。x64の場合-リンクは説明にあります)、インストールします。 Visual Studioに戻る-コードを書く時間です。

したがって、最初のステップは、Moleの構成をプロジェクトに追加することです。 テストプロジェクトにMolesおよびスタブタイプの新しいアイテムを追加し、名前としてPaymentsApp.molesを指定します。 ファイルの内容は非常に単純です。

<? xml version ="1.0" encoding ="utf-8" ? >

< Moles xmlns ="http://schemas.microsoft.com/moles/2010/" >

< Assembly Name ="PaymentsApp" />

</ Moles >






スタブが生成されるアセンブリは次のとおりです。 ソリューションエクスプローラーでは、生成されたすべてのファイルを確認することもできます。すべてのアセンブリは自動的に参照に追加されます。



これで、第2段階であるスタブの作成に直接進むことができます。 テストメソッドのコードに戻り、最初に追加します。

using PaymentsApp.Moles;





この名前空間は、構成によって生成されたアセンブリにあり、元のアセンブリの各クラスの特別なプロキシクラスを含みます-プレフィックスMで始まります。 興味のあるCacheManagerクラス(潜伏性のある静的メソッドを含む)はMCacheManagerと呼ばれます。 メソッドの場合、名前が<originalName> <Parameter1 type> <Parameter2 type>のプロパティが生成されます...したがって、対象のプロパティはGetClientInt32です。 このプロパティのタイプはFunc <int、Client>です。元のCacheManager.GetClientメソッドの代わりに実行されるデリゲートを受け入れます。

そのため、テストメソッドの先頭に次の行を追加します。

MCacheManager.GetClientInt32 = id => new Client( "Test" , 100);





ただし、テストを実行するには時期尚早です-メソッド内でMolesを使用できるようにするには、このメソッドのHostType属性を指定する必要があります。

[HostType( "Moles" )]





したがって、テストメソッドの最終形式は次のとおりです。

[TestMethod]

[HostType( "Moles" )]

[ExpectedException( typeof (AmountException))]

public void AcceptPaymentOverdraftTest()

{

MCacheManager.GetClientInt32 = id => new Client( "Test" , 100);

PaymentsApp.PaymentsCore core = new PaymentsCore();

core.AcceptPayment(1, 200);

}






これで、CacheManagerクラスの静的メソッドの代わりに、デリゲートが実行され、目的のモックオブジェクトが返されます。 つまり このテストでは、データベースの依存関係、キャッシュなどがなくなりました。 -また、コードを変更しなくても。



参照:

1) Moles-.NETの分離フレームワーク

2) ビデオ-Molesのクイックスタート(5分)

3) TypeMockアイソレーター

4) デモプロジェクトのソースコード



All Articles