C# と RhinoMocks を使用したテスト駆動開発のベスト プラクティス [終了]

StackOverflow https://stackoverflow.com/questions/124210

質問

私のチームがテスト可能なコードを作成できるようにするために、C# コード ベースをよりテストしやすくするためのベスト プラクティスの簡単なリストを作成しました。(ポイントの一部は、C# のモック フレームワークである Rhino Mocks の制限に言及していますが、ルールはより一般的にも適用される可能性があります。) 従うベスト プラクティスを持っている人はいますか?

コードのテスト容易性を最大限に高めるには、次のルールに従ってください。

  1. 最初にテストを作成し、次にコードを作成します。 理由:これにより、テスト可能なコードを作成し、コードのすべての行にテストが作成されるようになります。

  2. 依存関係注入を使用してクラスを設計します。 理由:目に見えないものを模擬したりテストしたりすることはできません。

  3. Model-View-Controller または Model-View-Presenter を使用して、UI コードをその動作から分離します。 理由:テストできない部分(UI)を最小限に抑えながら、ビジネスロジックをテストできます。

  4. 静的なメソッドやクラスを作成しないでください。 理由:静的メソッドは分離が困難または不可能であり、Rhino Mocks は静的メソッドをモックすることができません。

  5. クラスではなくインターフェースをプログラムします。 理由:インターフェイスを使用すると、オブジェクト間の関係が明確になります。インターフェイスは、オブジェクトがその環境から必要とするサービスを定義する必要があります。また、Rhino Mocks やその他のモック フレームワークを使用して、インターフェイスを簡単にモックすることができます。

  6. 外部依存関係を分離します。 理由:未解決の外部依存関係はテストできません。

  7. モックする予定のメソッドを仮想としてマークします。 理由:Rhino モックは非仮想メソッドをモックできません。

役に立ちましたか?

解決

確かに良いリストです。これについては次のような考えがあります。

最初にテストを作成し、次にコードを作成します。

高いレベルでは同意します。しかし、もっと具体的に言うと、「最初にテストを書いてから、 ちょうどいい そうしないと、単体テストが統合テストや受け入れテストのように見えてしまうのではないかと心配です。

依存関係注入を使用してクラスを設計します。

同意しました。オブジェクトが独自の依存関係を作成すると、それらを制御することはできません。制御の反転 / 依存関係の注入により制御が提供され、テスト対象のオブジェクトをモック/スタブなどで分離できるようになります。これは、オブジェクトを個別にテストする方法です。

Model-View-Controller または Model-View-Presenter を使用して、UI コードをその動作から分離します。

同意しました。プレゼンター/コントローラーであっても、スタブ/モック化されたビューとモデルを渡すことで、DI/IoC を使用してテストできることに注意してください。チェックアウト プレゼンターファースト 詳細については、TDD を参照してください。

静的なメソッドやクラスを作成しないでください。

これに同意するかどうかはわかりません。モックを使用せずに静的メソッド/クラスの単体テストを行うことができます。したがって、おそらくこれは、あなたが言及した Rhino Mock 固有のルールの 1 つです。

クラスではなくインターフェースをプログラムします。

私も同意しますが、理由は少し異なります。インターフェイスは、さまざまなモック オブジェクト フレームワークのサポートだけでなく、ソフトウェア開発者に大きな柔軟性を提供します。たとえば、インターフェイスがなければ DI を適切にサポートすることはできません。

外部依存関係を分離します。

同意しました。インターフェイスを使用して、独自のファサードまたはアダプター (必要に応じて) の背後に外部依存関係を隠します。これにより、Web サービス、キュー、データベースなどの外部依存関係からソフトウェアを分離できます。これは 特に チームが依存関係 (別名: 依存関係) を制御していない場合に重要です。外部の)。

モックする予定のメソッドを仮想としてマークします。

これは Rhino モックの制限です。モック オブジェクト フレームワークよりも手動でコード化されたスタブを好む環境では、その必要はありません。

そして、新たに考慮すべき点がいくつかあります。

創造的なデザインパターンを使用します。 これは DI に役立ちますが、コードを分離して他のロジックから独立してテストすることもできます。

を使用してテストを作成します Bill Wakeのアレンジ/アクト/アサートテクニック. この手法により、どのような構成が必要なのか、実際に何がテストされているのか、何が期待されているのかが非常に明確になります。

独自のモック/スタブを作成することを恐れないでください。 多くの場合、モック オブジェクト フレームワークを使用すると、テストが信じられないほど読みにくくなることがわかります。独自のものをロールすることで、モック/スタブを完全に制御でき、テストを読みやすい状態に保つことができます。(前の点を参照してください。)

単体テストの重複をリファクタリングして抽象基本クラスやセットアップ/破棄メソッドに変換する誘惑を避けてください。 そうすることで、単体テストを理解しようとする開発者から構成/クリーンアップ コードが隠蔽されます。この場合、重複をリファクタリングして排除することよりも、個々のテストを明確にすることの方が重要です。

継続的インテグレーションを実装します。 すべての「グリーンバー」にコードをチェックインします。ソフトウェアを構築し、すべてのチェックインで一連のユニットテストを完全に実行します。(もちろん、これ自体はコーディングの練習ではありません。ただし、ソフトウェアをクリーンで完全に統合した状態に保つための素晴らしいツールです。)

他のヒント

.Net 3.5 を使用している場合は、次のことを調べてください。 モク モッキング ライブラリ - 式ツリーとラムダを使用して、他のほとんどのモッキング ライブラリの非直感的なレコード応答イディオムを削除します。

これをチェックしてください クイックスタート テスト ケースがどれほど直感的になるかを確認するために、簡単な例を次に示します。

// ShouldExpectMethodCallWithVariable
int value = 5;
var mock = new Mock<IFoo>();

mock.Expect(x => x.Duplicate(value)).Returns(() => value * 2);

Assert.AreEqual(value * 2, mock.Object.Duplicate(value));

の違いを知る 偽物、モック、スタブ そしてそれぞれをいつ使用するか。

モックを使用してインタラクションを過剰に指定しないようにします。これによりテストが行​​われます 脆い.

これはとても役立つ投稿です!

コンテキストとテスト対象システム (SUT) を理解することが常に重要であることを付け加えておきます。既存のコードが同じプリンシパルに従っている環境で新しいコードを作成する場合、TDD プリンシパルに忠実に従うことがはるかに簡単になります。しかし、非 TDD レガシー環境で新しいコードを作成している場合、TDD の取り組みが見積もりや期待をはるかに超えて急速に膨れ上がる可能性があることがわかります。

完全に学術的な世界に住んでいる一部の人にとっては、スケジュールや納品は重要ではないかもしれませんが、ソフトウェアがお金である環境では、TDD の取り組みを効果的に活用することが重要です。

TDD は次の法則の影響を強く受けます。 限界利益の逓減. 。つまり、TDD への取り組みは、最大収益点に到達するまではますます価値があり、その後、TDD に投資された時間の価値はますます低くなります。

私は、TDD の主な価値は境界 (ブラックボックス) と、システムのミッションクリティカルな領域の時折のホワイトボックス テストにあると信じる傾向があります。

インターフェイスに対してプログラミングする本当の理由は、Rhino の作業を容易にすることではなく、コード内のオブジェクト間の関係を明確にすることです。インターフェイスは、オブジェクトがその環境から必要とするサービスを定義する必要があります。クラスは、そのサービスの特定の実装を提供します。役割、責任、協力者に関する Rebecca Wirfs-Brock の『オブジェクト デザイン』の本を読んでください。

良いリストだ。確立したいことの 1 つは、クラスが別のライブラリ、名前空間、ネストされた名前空間に存在する必要がある場合です。これについては、私自身考え始めたばかりなのであまりアドバイスできません。事前にライブラリと名前空間のリストを作成し、チームが会議を行って 2 つをマージするか、新しいものを追加するかを決定するよう義務付けることもできます。

ああ、私がやっていることであなたもやりたいと思うかもしれないことを思いつきました。通常、クラスポリシーごとにテストフィクスチャを備えた単体テストライブラリがあり、各テストが対応する名前空間に配置されます。また、私は別のテスト ライブラリ (統合テスト?) を持っている傾向があります。 BDD スタイル. 。これにより、メソッドが何を行うべきか、またアプリケーションが全体的に何を行うべきかを指定するテストを作成できます。

これが私がやりたいと思ったもう一つのことです。

TestDriven.Net や NAnt からではなく単体テスト Gui からテストを実行する予定がある場合は、単体テスト プロジェクト タイプをライブラリではなくコンソール アプリケーションに設定する方が簡単であることがわかりました。これにより、テストを手動で実行し、デバッグ モードでステップ実行することができます (これは、前述の TestDriven.Net が実際に実行できます)。

また、私はいつも、馴染みのないコードやアイデアをテストするために Playground プロジェクトを開いたままにしたいと考えています。これはソース管理にチェックインしないでください。さらに良いのは、開発者のマシンのみにある別のソース管理リポジトリに置く必要があることです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top