複雑なアプリケーションでの単体テスト

複雑なアプリケーション(たとえば、100K LOC以上)を開発する場合、健全な心と地味なメモリを備えた開発者は、一般にテストを、特に単体テストを使用する必要を否定しません。 これは、すべての開発者がアプリケーションを作成する創造的なプロセスから意味のない作業を除外しようとするという事実と同じです。 複雑なアプリケーションのコンテキストで単体テストについて話す場合、必要性と無意味さを区別する行はどこにありますか? 私はこのことについていくつか考えを述べました。







予定



ウィキペディア







単体テスト、または単体テストは、プログラムのソースコードの個々のモジュールの正確性を確認できるプログラミングプロセスです。



アイデアは、重要な関数やメソッドごとにテストを書くことです。 これにより、次のコード変更がリグレッションにつながっているかどうか、つまりプログラムのテスト済みの場所でエラーが発生しているかどうかをすばやく確認でき、そのようなエラーの検出と除去が容易になります。

すべてが明確であるかのようです。 5行のコードがあります。







class Calculator { public function add($a, $b) { return $a + $b; } }
      
      





単体テストがあります( すでに10行ですが、テストの行数がテストされたコードの行数を超える場合、これは単体テストでは正常です ):







 class CalculatorTests extends PHPUnit_Framework_TestCase { private $calculator; protected function setUp() { $this->calculator = new Calculator(); } public function testAdd() { $result = $this->calculator->add(1, 2); $this->assertEquals(3, $result); } }
      
      





このテストにより、コードのロジックを確認し、何かまたは誰かがこのロジックに違反した場合にエラーを検出できます。 単体テストはアプリケーション全体とは別にコードをテストするため、非常にシンプルで高速であり、開発中のコードの重要な部分の「健全性」を非常に短時間で評価できます。







単体テストだけでは、アプリケーション全体が正しく機能することは保証されませんが、テストのリストの最初の基本段階です。













写真は、その三角形といくつかのタイプのテストの階層化されたリストのみのためにインターネットから撮影されました;パーセント数およびその他の詳細は上記の文脈では重要ではありません;







些細な些細さ



" ...すべての非自明な関数またはメソッドのテストを作成します。 "







特定の仕様に従ってロジックを実装するコードを使用すると、すべてが明確になります。 そして、このロジック自体がそうではないコードをどうするか? たとえば、DTOのよ​​うなクラスのアクセサーを使用しますか?







ネットワークマインドは、コード内で次のようなエラーが発生する可能性がゼロではないにもかかわらず、そのようなケースを些細なものとして分類します。







 public function getDateCreated() { return $this->_dateUpdated; }
      
      





このようなエラーの可能性は、コード内の検索と置換のプログレッシブテクニックを大量に適用することで大幅に増加し、プロジェクトの成長とサブジェクトエリアの詳細への完全な没入によりプログレッシブテクニックを使用する要望が高まります。







無意味と必要性の妥協点は、DTOのよ​​うなオブジェクトを使用する他のささいなクラス(サービスなど)をテストするためにデータを準備するときにプロセッサにアクセスするか、assertを介して戻った後に結果を確認することです:







 $in = new InDto(); $in->setId(4); $out = $service->callMethod($in); $this->assertEquals('success', $out->getStatus());
      
      





この場合、テストされたコードを他のアプリケーションコードから分離するという原則に違反しています。 まあ、彼は2つの非常に良いオプションの3つ目を選ぶ妥協であり、悪いものではありません。







自明でない自明性



すべてのオブジェクト指向開発者は、遅かれ早かれSOLIDという略語に出くわしました(最初は「 S 」はSRPに対応し、「 クラスには1つの責任しかありません 」)。 この原則の体系的で一貫した適用は、一方では特定のクラスのコードの簡素化につながり、他方ではクラスの数とそれらの間の関係の増加につながります。 成長の問題を克服するために、 モジュラーアプローチマルチレベルアーキテクチャ 、および制御反転が使用されています。 ネットでは、個々のメソッドのそのような実装まで、「 特定のクラスのコードを単純化する 」という形で堅実な利益を得ています。







 public function execute($in) { $order = $in->getOrder(); $this->_service->saveOrder($order); $this->_otherSrv->accountOrder($order); }
      
      





このようなコードのテストは、無意味さと必要性の境界で再びバランスをとります-基本的に、テストはスタブ/モックの作成と、対応するメソッドが適切な順序で呼び出されることの検証に行き着きます。 ソースコードを使用してファイルのコントロールコピーを作成し、コントロールコピーからの現在のコードのすべての逸脱のテストについて報告する場合、まったく同じ効果をはるかに速く達成できます。







Dimitar Ginevの同僚 、このような場合、コードを2つのクラスのクラス( オーケストレーター意思決定者 )に分割し、2番目のカテゴリーコードのみをテストでカバーすることを推奨しています。







コードカバレッジ



コードの品質を評価するための優れた指標は、テストでのコードのカバレッジ率です 。 この割合は、ソースコードを含む別のファイルと、プロジェクトのコードベース全体(たとえば、 Magento 2.1.1モジュールのテストカバレッジ)の両方について計算できます。 コードのカバレッジにより、ソースコードの開発における問題領域を視覚的に評価することが可能になり、意味のあるコードを100%網羅するよう努める必要があります。 さらに、開発中のアプリケーションが複雑になるほど、その中に意味のあるコードが含まれ、100%のカバレッジがより重要になり始めます。 ユニットテストは、このメトリックの計算に結果を使用するのに非常に適した候補です。これも、相互(現在およびテストされていない残りのコードから)独立していることと実行速度のためです。







プロジェクト内のすべてのコードのカバレッジは、次の2つの方法で最大100%にできます。









最初の方法は、 各自明な関数またはメソッドごとにテストも作成する必要があることを意味します。これにより、意味がなくなります。 2番目の方法は、重要なコードのテストをスキップすることに悩まされます。







では、バランスはどこにありますか?



コミュニティは些細な機能をテストする必要がないことに同意しているため、コードが単純であるほど、または開発者が独創的であればあるほど、一般にテストを作成し、特に単体テストを作成する理由が少なくなります。 逆に、コードが複雑であるほど、または開発者が平凡であるほど、より多くの理由があります。 つまり、10万行のコードだけでプロジェクトを開発している場合、テストなしで完全に実行できますが、別の開発者(あなたほど優秀ではない)がプロジェクトに接続するとすぐに、テストを作成する必要性が劇的に増加します。 また、この開発者が後輩でもある場合、テストが不可欠になります。 天才であっても、後輩がお気に入りのコードでミスを犯す熱意からあなたを救うことができます。







開発の初期段階で、単純なコード(アクセサーとオーケストレーター)を単体テストから完全に除外できる場合、プロジェクトが増え、プロジェクトで作業する人が増えれば増えるほど、些細なコードが残ります。 極端な場合、コードが公開されている(つまり、その夜プログラマーになることを決めた退屈した駐車警備員からプルリクエストが来る可能性がある)場合、コードのすべての行は単体テストでカバーされるべきです。







参照資料






All Articles