88

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

コードのテスト容易性を最大化するには、次の規則に従います。

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

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

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

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

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

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

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

4

7 に答える 7

59

間違いなく良いリストです。ここにいくつかの考えがあります:

最初にテストを書き、次にコードを書きます。

高いレベルで同意します。しかし、もっと具体的に言えば、「最初にテストを書き、次にテストに合格するだけのコードを書き、それを繰り返す」ということです。そうしないと、単体テストが統合テストや受け入れテストのようになってしまうのではないかと心配しています。

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

同意した。オブジェクトが独自の依存関係を作成する場合、それらを制御することはできません。制御の反転 / 依存性注入によってその制御が可能になり、モック/スタブなどを使用してテスト対象のオブジェクトを分離できます。これは、オブジェクトを分離してテストする方法です。

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

同意した。プレゼンター/コントローラーでさえ、DI/IoC を使用して、スタブ/モック ビューとモデルを渡すことでテストできることに注意してください。詳細については、 Presenter First TDD をご覧ください。

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

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

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

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

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

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

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

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

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

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

Bill Wake の Arrange/Act/Assert 手法を使用してテストを記述します。この手法により、必要な構成、実際にテストされているもの、および期待されるものが非常に明確になります。

独自のモック/スタブを作成することを恐れないでください。多くの場合、モック オブジェクト フレームワークを使用すると、テストが非常に読みにくくなります。独自のロールを作成することで、モック/スタブを完全に制御できるようになり、テストを読みやすく保つことができます。(前のポイントに戻って参照してください。)

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

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

于 2008-09-24T05:32:30.427 に答える
10

.Net 3.5 を使用している場合は、Moqモッキング ライブラリを調べることをお勧めします。これは、式ツリーとラムダを使用して、他のほとんどのモッキング ライブラリの非直感的な記録と応答のイディオムを削除します。

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

// 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));
于 2008-09-24T05:44:57.337 に答える
6

フェイク、モック、スタブの違いと、それぞれをいつ使用するかを理解します。

モックを使用して相互作用を過度に指定することは避けてください。これにより、テストが脆弱になります。

于 2008-09-24T05:42:26.207 に答える
4

これは非常に役立つ投稿です!

Context と System Under Test (SUT) を理解することが常に重要であることを付け加えておきます。既存のコードが同じプリンシパルに従っている環境で新しいコードを記述している場合、TDD プリンシパルを文字どおりに従うことははるかに簡単です。しかし、TDD 以外のレガシー環境で新しいコードを作成している場合、TDD への取り組みが見積もりや期待をはるかに超えて急速に膨れ上がることに気付きます。

完全にアカデミックな世界に住んでいる人にとっては、タイムラインと配信は重要ではないかもしれませんが、ソフトウェアがお金である環境では、TDD の取り組みを効果的に利用することが重要です。

TDD は、限界利益率減少の法則の影響を強く受けます。要するに、TDD に対するあなたの努力は、最大の利益が得られるポイントに到達するまでますます価値が高まります。

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

于 2009-05-06T02:23:23.750 に答える
2

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

于 2009-09-06T19:45:38.720 に答える
1

良いリスト。あなたが確立したいと思うかもしれないことの 1 つは、クラスが別のライブラリ、名前空間、ネストされた名前空間にある必要がある場合です。事前にライブラリと名前空間のリストを把握し、チームが会議を開き、2 つをマージするか新しいものを追加することを決定するように指示することもできます。

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

于 2008-09-24T00:06:29.197 に答える
0

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

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

また、よく知らないコードやアイデアをテストするために、Playground プロジェクトを常に開いておくのが好きです。これは、ソース管理にチェックインしないでください。さらに良いことに、それは開発者のマシンのみの別のソース管理リポジトリにある必要があります。

于 2008-09-24T13:27:15.153 に答える