選択的ユニットテストまたはシンコントローラー

Habrで最近言及された記事に加えて、ユニットテストでコードを100%完全にカバーすることはほとんどすべての場合経済的に実行可能ではありません ...これには作業時間の不当な費用が必要であり、コードを維持するためのコストが増加します。本日、 Pro ASP.NET MVCおよびPro ASP.NET MVC V2の著者であるSteve Sandersonについての考えを公開したいと思います



エントリー


3年前から単体テストを書いており、1年前から専門的にTDDに携わっています。 そしてこれまでずっと、私はそのようなことに何度も気づきました:ユニットテストはある種のコードに対して簡単かつ自然に書かれ、コードの品質を大幅に改善しますが、他の人にとっては多大な努力を必要としますが、欠陥を排除するのにはまったく役立ちませんが、むしろ反対です-リファクタリングまたは改善を試みる場合にのみ障害になります。



そして、これは驚くことではありません。人生のさまざまな分野で確立されたアプローチのほとんどすべては、実際には特定の状況でのみ有効であり、他の条件ではその利点を失います。 それがここにあります:多くの開発者は、単体テストを書くことが常に良いとは限らないことに同意するでしょう。



したがって、このメモを書く目的は次のとおりです。

  1. この特定のコードの単体テストの価値を実際に決定するものを理解します。
  2. 各機能ブロックの実装を開始する前に、100%のカバレッジの必要性とテストの義務的な記述に関する広範な意見の矛盾を示します。


テストの利点


単体テストを行うことの利点のリストは、主に2つに減らすことができます。 次のことができます。

  1. コードを作成するときにコードを直接設計します。
  2. 実装が意図したとおりに機能することを確認してください。


しかし、疑問が生じます。なぜ追加の設計および検証システムが必要なのか、コード自体にはデバイスとアプリケーションの動作に関する情報が含まれていないのですか? また、テストが根本的に新しい情報を提供しない場合、設計されたシステムの正確性をどのように確認しますか? 「再現性の原則」( DRY )はどうですか?



私にとって個人的には、タスクの最初の考えでその実装のコードが明白にならない場合、それを書くために座って考えなければならないことを意味し、追加のヘルプ(例えば、ユニットテストの形で)、すべてが正しく動作することを確認できるようにします、非常に役立つでしょう。 たとえば、ビジネスルールのシステムを開発している場合、または複雑な階層式を解析している場合、考えられるすべてのコード動作の分岐をすぐに追跡することはできません。 そのような場合、単体テストは非常に価値があります。



逆もまた同様です。コードがシンプルで明白であり、一目でそれが何をするのかすぐに明らかな場合、単体テストの利点は無効になります。 たとえば、現在の日付と空きディスク領域を受け取り、このデータを別のメソッドに転送するメソッドを作成します。 この場合、コードはそれ自体を物語っています。追加の単体テストに追加するものは何もありません。



そのため、単体テストの利点は、コードの複雑度に直接依存します。



試験価格


製品のコストに影響する要因には次のものがあります。

  1. テストの作成に費やした時間。
  2. コードのリファクタリングまたは他の変更を行った後のテストの修正と最終化に費やされた時間。
  3. いくつかのテストが失敗し、書き直さなければならないという期待のために、コードを改善することへの恐怖。




もちろん、テストシステムをサポートするコストは、 さまざまな推奨事項に従うことで削減できますが、それでも比較的大きいままでかまいません。



私の観察によると、特定のコードの単体テストの総コストは、コードの残りの部分に存在する依存関係の数と非常に相関しています。 なぜだろう?



初期作成。 メソッドが他のブロックに依存せず、1つのパラメーターを取る通常の関数のように機能する場合、単体テストは入力データと出力データ間の対応のリストになります。 しかし、メソッドが多くのパラメーターを取り、クラスのプロパティを介して多くの外部サービスとやり取りする場合は、一連の偽(モック)オブジェクトを作成する必要があります。 しかし、この作業のコストは次の段落に比べて小さいです。



サポート。 コードブロックに存在する依存関係が多いほど、このコードが変更を余儀なくされることが多くなることが確立されました(これがコードの不安定性の判定方法です)。 そして、理由は明らかです。これらの依存関係のそれぞれについて、一定期間、そのシグネチャまたは動作が変更される可能性があり、その結果、コードと対応するテストを更新する必要が生じます。



これらの問題は、クリーンなインターフェースで作業しているときにIoCDI )を使用する場合にも同様に当てはまることに注意してください。



そのため、単体テストのコストは、コードセクションの依存関係の数に直接依存します。



テストのコストと利点のグラフィカルな表現


画像



この意図的に簡略化された図は、4種類のコードを示しています。



最後に練習。 では、ASP.NET MVCはどうでしょうか?


ASP.NET MVCでは、一見したところアプリケーションロジックはコントローラーに配置するのが最も簡単です。 また、コントローラーにビジネスルールを押し込み続ける間、後者は非常に面倒になります。コントローラー自体に複雑なロジックが蓄積され、同時に多くのオブジェクトに依存するため、テストには十分な費用がかかります。 馬、人、またはむしろ、異なるアプリケーション層のタスク(いわゆるアンチパターン「シックコントローラー」 )がまとまります。



このような混乱を避けるために、アプリケーションロジックの独立した部分をモデルレベルのクラスに分解する必要があります(式はごめんなさい)。 次に、純粋なコントローラーの本来の目的と矛盾する部分を他の部分から分離し、それらをActionFilters、独自のModelBinders、およびActionResultsに配置できます。



このようにコントローラーを構成すればするほど、コントローラーはよりシンプル、クリーン、美しくなり、最終的にはアプリケーションの他のレイヤー間の相互作用を管理するコーディネーターが純粋な水に退化すると同時に、独自の追加ロジックなしで一貫したシステムに成長します。 言い換えれば、コントローラーの構造が優れているほど、ダイアグラムの右下部分に引き寄せられ、テストの感覚が失われます。



コントローラの目的は、さまざまなサービスのさまざまなAPIの単なる待ち合わせ場所にすることです。 このようなコントローラーのコードは簡単に読み取り可能で、多くの依存関係を結び付けます。 経済的利益の観点から、コントローラーの単体テストではなく、統合テストのリファクタリングと記述に時間をかけると、私の仕事ははるかに効果的であるという結論に達しました。



おわりに


誰かが私の言葉を誤解する可能性がある場合:実際、私はユニットテストやTDDに反対していません。 私の主なポイントは次のとおりです。



上記のすべては、私の観察結果の単なる説明であり、あなたの観察結果と一致しない場合があります。



オリジナル記事



おそらくスコット・ベルバー(スコット・ベルウェア)の言葉を思い出すだけである:「TDDはテストすることではなく、デザインすることだ」。



All Articles