web-dev-qa-db-ja.com

テスト駆動開発を行う方法

アプリケーション開発で2年以上の経験があります。この2年間、開発に対する私のアプローチは次のとおりでした。

  1. 要件を分析する
  2. Identity Coreコンポーネント/オブジェクト、必要な機能、動作、プロセス、およびそれらの制約
  3. クラスの作成、クラス間の関係、オブジェクトの動作と状態に対する制約
  4. 関数を作成し、要件ごとに動作制約を使用して処理する
  5. アプリケーションを手動でテストする
  6. 要件の変更によりコンポーネント/機能が変更される場合は、アプリケーションを手動でテストします

最近、TDDを導入しました。開発されたコードが存在する強力な理由があり、展開後の多くの問題が軽減されているため、これは開発を行うための非常に良い方法だと感じています。

しかし、私の問題は、最初にテストを作成できないことです。むしろ、実際にコンポーネントを作成する前に、コンポーネントを特定し、それらのテストを作成するだけです。私の質問は

  1. 私はそれをやっていますか?そうでなければ正確に私は変更しなければなりません
  2. 作成したテストで十分かどうかを確認する方法はありますか?
  3. 1 + 1 = 2に相当する可能性のある非常に単純な機能のテストを作成することは良い習慣ですか、それとも単なるやりすぎですか?
  4. 機能を変更して、要件が変更されたかどうかをテストするのは良いことですか?
15
Yogesh

私はそれをやっていますか?そうでなければ正確に私は変更しなければなりません

その短い説明だけで言うのは難しいですが、あなたはnot正しくやっていると思います。注:私はあなたがしていることがうまくいかない、または何らかの形で悪いことを言っているのではありませんが、TDDをしているわけではありません。中央の「D」は「ドリブン」を意味し、テストはすべて、開発プロセス、コード、デザイン、アーキテクチャ、everythingをドライブします。

テストは、何を書くべきか、いつ書くべきか、次に何を書くべきか、いつ書くのをやめるべきかを教えてくれます。彼らはあなたにデザインとアーキテクチャを教えてくれます。 (設計とアーキテクチャは、リファクタリングを通じてコードから生まれます。)TDDはテストに関するものではありません。それは最初にテストを書くことでもありません:TDDはテストがあなたを運転できるようにすることです、それらを最初に書くことはそのための必要な前提条件にすぎません。

実際にコードを書き留めるか、完全に具体化したかは関係ありません。コード(のスケルトン)を頭に書いてから、そのコードのテストを記述します。それはTDDではありません。

その習慣を手放すのはhardです。本当に、本当に難しい。経験豊富なプログラマにとっては特に難しいようです。

キース・ブレイスウェイトは、彼が呼び出すエクササイズを作成しました TDDのように意味があります 。これは、厳密に従う必要があり、TDDをより厳密に適用するように設計されている一連のルール( ncle Bob MartinのTDDの3つのルール に基づいていますが、はるかに厳格です)で構成されています。ペアプログラミング(ペアがルールに違反していないことを確認できるようにするため)とインストラクターとの組み合わせが最適です。

ルールは次のとおりです。

  1. 正確に1つの新しいテストを記述します。これは、ソリューションの方向性を示すと思われる、最小のテストです。
  2. それが失敗するのを見てください。コンパイルの失敗は失敗としてカウントされます
  3. (1)パスからテストを作成しますテストメソッド内で可能な最小の実装コードを記述します。
  4. 重複を取り除くためにリファクタリングし、そうでなければデザインを改善するために必要に応じて。これらの動きの使用については厳格にしてください:
    1. 新しいメソッドが必要です。リファクタリングの時間まで待ってから、…これらのいずれかを実行して、新しい(非テスト)メソッドを作成します。 :
      • 推奨:(3)に従って作成された実装コードに対してExtractメソッドを実行して、テストクラスに新しいメソッドを作成する、または
      • 必要な場合:(3)に従って実装コードを既存の実装メソッドに移動する
    2. 新しいクラスが必要です—リファクタリング時間まで待機してから…移動メソッドの宛先を提供するために、他の理由なしに非テストクラスを作成します
    3. 他の方法ではなく、Move Methodを実行して、実装クラスにメソッドを入力します。

通常、これにより、「実際のデザインを頭の中で想像し、そのデザインを強制するためのテストを作成し、作成する前にすでに構想していたデザインを実装する」という、頻繁に実施される「疑似TDDメソッド」とは非常に異なるデザインがもたらされます。テスト」。

人々のグループが疑似TDDを使用して三目並べゲームのようなものを実装する場合、それらは通常、Boardsの3x3配列を含むある種のIntegerクラスを含む非常に類似した設計になります。そして、プログラマーの少なくとも一部は、実際にはこのクラスをテストなしで作成しているでしょう。なぜなら、彼らは「必要になることを知っている」か、「テストを書くために何かを必要としている」からです。ただし、その同じグループにTDDを適用するように強制すると、多くの場合、非常に異なる非常に異なる設計になり、Boardにリモートで類似したものを使用しなくなります。

作成したテストで十分かどうかを確認する方法はありますか?

彼らがすべてのビジネス要件をカバーするとき。テストは、システム要件のエンコーディングです。

1 + 1 = 2に相当する可能性のある非常に単純な機能のテストを作成することは良い習慣ですか、それとも単なるやりすぎですか?

繰り返しになりますが、逆方向にあります。機能のテストを記述しません。テストの機能を記述します。テストに合格するための機能が取るに足らないものであることが判明した場合、それはすばらしいことです。あなたはシステム要件を満たし、それのために一生懸命働く必要さえありませんでした!

機能を変更して、要件が変更されたかどうかをテストするのは良いことですか?

いいえ、その逆です。要件が変更された場合、その要件に対応するテストを変更し、テストが失敗するのを監視してから、コードを変更して合格とします。テストalwaysが最初に来ます。

これを行うのは難しいです。ある種の「筋肉の記憶」を構築してポイントに到達するには、数十、おそらく数百時間熟練した練習が必要です。締め切りが迫っていて、プレッシャーにさらされているときに、それについて考える必要さえあり、これを行うことはfastestとなり、最も自然な作業方法になります。

19
Jörg W Mittag

開発アプローチを「トップダウンのみ」のプロセスとして説明します。つまり、より高い抽象化レベルから始めて、より詳細に進んでいきます。 TDDは、少なくとも一般的な形では、「ボトムアップ」手法です。そして、ほとんどが「トップダウン」で作業している人にとって、「ボトムアップ」で作業することは実際に非常に珍しい場合があります。

では、どうすれば開発プロセスに「TDD」を追加できるでしょうか。最初に、あなたの実際の開発プロセスは、上で説明したように必ずしも「トップダウン」であるとは限らないと思います。ステップ2の後、おそらく他のコンポーネントから独立しているいくつかのコンポーネントを識別しているでしょう。場合によっては、最初にこれらのコンポーネントを実装することを決定します。これらのコンポーネントのパブリックAPIの詳細は、おそらく要件だけではなく、設計上の決定にも従います。これは、TDDから始めることができるポイントです。コンポーネントの使用方法、および実際のAPIの使用方法を想像してください。そして、そのようなAPIの使用法をテストの形でコーディングし始めると、TDDから始めたばかりです。

第2に、他の存在しないコンポーネントに最初に依存するコンポーネントから始めて、より「トップダウン」でコーディングする場合でも、TDDを実行できます。学習する必要があるのは、これらの他の依存関係を最初に「モックアウト」する方法です。これにより、下位レベルのコンポーネントに進む前に、上位レベルのコンポーネントを作成してテストできます。トップダウン方式でTDDを実行することに関する非常に詳細な例は、 このRalf Westphalのブログ投稿 にあります。

5
Doc Brown

私はそれをやっていますか?そうでなければ正確に私は変更しなければなりません

あなたはうまくやっています。

作成したテストで十分かどうかを確認する方法はありますか?

はい、 テスト/コードカバレッジツール を使用します。マーティンファウラーは、テストカバレッジについて 良いアドバイス をいくつか提供しています。

1 + 1 = 2に相当する可能性のある非常に単純な機能のテストを作成することは良い習慣ですか、それとも単なるやりすぎですか?

一般に、いくつかの入力を与えられたときに何らかの結果が得られると期待される関数、メソッド、コンポーネントなどは、単体テストの良い候補です。ただし、(エンジニアリング)生活のほとんどの場合と同様に、トレードオフを検討する必要があります。単体テストを作成することで労力が相殺され、長期的にはより安定したコードベースになりますか?一般に、重要/重要な機能のテストコードを最初に作成することを選択します。後でコードのテストされていない部分に関連するバグが見つかった場合は、テストを追加します。

機能を変更して、要件が変更されたかどうかをテストするのは良いことですか?

自動テストを使用することの良い点は、変更が以前のアサーションに違反しているかどうかをすぐに確認できることです。要件が変更されたためにこれが予想される場合は、テストコードを変更しても問題ありません(実際、純粋なTDDでは、要件に応じて最初にテストを変更し、次に新しい要件を満たすまでコードを採用します)。

3
miraculixx

最初にテストを作成することは、ソフトウェアを作成するためのまったく異なるアプローチです。テストは、適切なコード機能検証のツール(すべて合格)であるだけでなく、設計を定義する力でもあります。テストカバレッジは有用なメトリックスかもしれませんが、それ自体が目標であってはなりません。TDDの目標は、コードカバレッジの適切な%に到達することではなく、コードを書く前にテスト可能性について考えることです。

最初にテストを書くことに問題がある場合は、TDDの経験者とペアプログラミングのセッションを行うことを強くお勧めします。これにより、アプローチ全体についての「考え方」の実践的な経験を得ることができます。

もう1つの良いことは、TDDを使用して最初の行からソフトウェアが開発されているオンラインビデオを視聴することです。かつてTDDを紹介するのによく使ったのは、James Shoreによる Let's Play TDD でした。見てみましょう。これは、新しい設計がどのように機能するか、テストを作成するときにどのような質問をする必要があるか、そして新しいクラスとメソッドがどのように作成、リファクタリング、反復されるかを示します。

作成したテストで十分かどうかを確認する方法はありますか?

これは間違った質問だと思います。 TDDを行う場合、ソフトウェアを作成する方法としてTDDと新しい設計を行うことを選択しました。追加する必要のある新機能が常にテストから始まる場合、それは常にそこにあります。

1 + 1 = 2に相当する可能性のある非常に単純な機能のテストを作成することは良い習慣ですか、それとも単なるやりすぎですか?

明らかにそれは依存します、あなたの判断を使用してください。メソッドがパブリックAPIの一部ではない場合、パラメーターのnullチェックのテストを記述したくないのですが、それ以外の場合、メソッドAdd(a、b)が実際にa + bを返すことを確認しないのはなぜですか?

機能を変更して、要件が変更されたかどうかをテストするのは良いことですか?

繰り返しになりますが、コードに変更または新しい機能を追加する場合、新しいテストを追加する場合でも、要件が変更されたときに既存のテストを変更する場合でも、テストから始めます。

3
Paul