すぐにすべてをドロップして、単体テストの作成を開始する理由

私の最初のTDDの経験で、洞察が私に現れました。 過去2〜3年、「TDDは良い」、「TDDが必要」という情報があらゆる側面から攻撃されてきたため、脳は本能的に課された情報に抵抗し始めます。 それ以前は、商用プロジェクトでTDDを練習したことはありませんでしたが、始めたときはすべてが適切に機能していました。 誰からも聞いたことがない、自動テストに関する興味深い視点を示したいと思います。



過去1年間、私はTDDでさえもなく、「TDDを実践していないなら、今すぐ始めてください」と明確に述べている優れたプログラミング/設計の実践について、いくつかの良い本を読みました。 しかし、とにかく、理論を十分に読み直した後、著者のそのような忍耐と自信がどこから来たのか、それが誰にとっても正しいことであるかは完全には明らかではありませんでした。



なぜコンパイラが必要なのですか?


コンパイルしますか? 私はかつてそれだけではないことに気づきました。 より正確には、ある種のバイナリ、DLLを取得するためではありません。 コードを入力するとき、時々エラーのあるウィンドウを確認し、何かが表示されたら修正します。 この素晴らしい機会は、バックグラウンドでスピンし、単純なエラーの存在をコードでチェックするパーサーによって提供されます。 しかし、時にはこれで十分ではありません。 コンパイラは、すべてのプロジェクトソースをコンパイル/コンパイルしてエラーを検出する必要がある場合があります。 たとえば、ASP.NETでは、ユーザーコントロールからパブリックメソッドを削除しますが、コンパイラはこのユーザーコントロールを再構築する必要があるため、エラーは表示されません。 このような場合、プロジェクトを完全に再構築する必要がありますが、アセンブリの結果として得られたものは基本的に必要ないことに注意してください。この段階では、エラーの有無に関する情報のみが重要でした。



私は何を得ていますか?


さらに、この状況でのコンパイラは、主にプログラミングエラーを示すために必要です。 通常、これらは単純なエラーですが、コンパイラが直接エラーを指すため、コンパイラが大好きです。 疎結合アーキテクチャのマイナス面の1つを覚えていますか? 遅延バインディングが優先され、継承よりも合成を優先するという事実により、コードの作成中に多くのエラーをキャッチできなくなりました。



class Darth { public void FeelForce() { ... } public void DoHeavyBreath() { ... } } class Luke : Darth { public void DefeatAllEnemies() { ... } } void main() { Luke luke = new Luke(); luke.FeelForce(); luke.DefeatAllEnemies(); luke.DoHeavyBreath(); // ,   ,     }
      
      







LukeクラスのDoHeavyBreathメソッドの呼び出しは、コンパイラーには見えない論理エラーです。 これは、より高いレベルの間違いです。 しかし、プログラミングは毎年上向きになり、より抽象的なものになりつつあるため、複雑さに対処するためのツールが必要です。 必要なツールの1つは、より高いレベルのエラーのパーサーです。 コンパイラが構文エラーを指摘するように。



上記のコードは、リテラシーを高めるために次のように書き換える必要があります。



 abstract class Jedi { public void FeelForce() { ... } public virtual void DefeatAllEnemies() { throw new NotImplementedException(); } public virtual void DoHeavyBreath() { throw new NotImplementedException(); } } class Darth : Jedi { override void DoHeavyBreath() { ... // do heavy breath } } class Luke: Jedi { override void DefeatAllEnemies() { ... // defeat all enemies } } void main() { Luke luke = new Luke(); luke.FeelForce(); luke.DefeatAllEnemies(); luke.DoHeavyBreath(); }
      
      







何が変わった? 私たちは皆同じ論理エラーを持っていますが、コンパイラはまだそれを検出できません。 しかし、TDDを使用してこのエラーを検出できます。 mainメソッドをテストするためのメソッドを作成しています。 最も簡単な方法で



 void test_that_luke_cannot_do_heavy_breath() { try { main(); } catch(NotImplementedException ex) { Assert.Fail("Unimplemented method was called!"); } }
      
      







私は個人的にこのアプローチで、高レベルのアーキテクチャの複雑さを克服するためのツールに過ぎないと考えています。 脳には独自の限界があり、それをカバーすることができ、必要なツールはこれらの限界を拡大します。 高レベルの抽象化では、コンパイラはエラーの大部分をカバーできないため、「エラーへのポインタ」としての役割を失います。 TDDは可能です。 もちろん、この手法は引き続き開発されます。 理想的には、開発者はプロジェクトをコンパイルする前にすべての既存のバグ(論理的なものを含む)を知っている必要があり、TDDが主に関連付けられている既存および将来のツールによって支援されます。 この開発は気づかれることさえあります。 興味がある人は、Visual StudioのNCrunchについて読むことができます。 他のIDEでは、継続的なテストに関連するツールも利用できると思います。 簡単に言えば、このツールはバックグラウンドで常に単体テストを実行し、再コンパイルせずにコードを記述するとすぐにテスト結果が表示されます。 バックグラウンドのコンパイラが構文エラーを検索し、検出したときに生成する方法といくつかの類似点に気付くでしょう。 そして今、ツールは非常にスマートになったため、論理エラーも表示されます。 もちろん、テストを自分で作成しなければならず、何らかの論理的なエラーを見失う可能性があるという事実に不満を表すことができますが、これはまだ先だと思います。 おそらく、テスト自体はビジネスロジックの正式な記述から生成されるでしょう。 いずれにせよ、そうでないことを叫ぶよりも、あることを喜ぶほうがよい。



All Articles