TDDを使用して初期APIを正しく取得する方法


12

私はTDDでの最初の試みであるので、これはかなりばかげた質問かもしれません。私はそれがもたらす自信とコードの一般的な構造が大好きでしたが、1クラスのおもちゃの例よりも大きなものに適用し始めたとき、私は困難に直面しました。

ある種のライブラリを作成しているとします。あなたはそれが何をしなければならないか、それがどのように実装されるべきかについての一般的な方法を知っています(アーキテクチャ上)、しかしあなたはあなたがコードとしてあなたのパブリックAPIに変更を加える必要があることを「発見」し続けます。おそらく、このプライベートメソッドを戦略パターンに変換する必要があり(テストでモックされた戦略を渡す必要があります)、おそらく責任をあちこちに置き忘れて、既存のクラスを分割する必要があります。

既存のコードを改良する場合、TDDは非常に適しているように見えますが、最初からすべてを記述する場合、テストを作成するAPIは、事前に大きな設計を行わない限り、少し「ぼやけ」ます。シグネチャ(およびその部分の動作)が変更されたメソッドで既に30のテストがある場合はどうしますか?それは一度追加すると変更する多くのテストです。


3
1つのメソッドで30のテスト?その方法は非常に複雑すぎるか、あなたが書いているテストが多すぎるように思えます。
ミントス

さて、私は自分の主張を表現するために少し誇張したかもしれません。コードをチェックした後、通常、テストごとにメソッドが10個未満で、そのほとんどが5未満です。しかし、「戻って手動で変更する」部分全体が非常にイライラしています。
Vytautasマッコニス

6
@Minthos:私は頭の上の6つのテストを考えることができます。文字列を取得するメソッドはしばしば失敗するか、最初のドラフトの書き込みでパフォーマンスが低下します(ヌル、空、長すぎる、適切にローカライズされていない、パフォーマンスのスケーリングが悪い) 。コレクションを取得するメソッドについても同様です。自明でない方法の場合、30は大きく聞こえますが、非現実的ではありません。
スティーブンエバーズ

回答:


13

あなたは何を呼び出す「アップフロントの大きなデザイン」私は呼んで「あなたのクラスのアーキテクチャの賢明な計画を。」

単体テストからアーキテクチャを成長させることはできません。ボブおじさん もそう言っています。

アーキテクチャを考えていない場合、代わりにアーキテクチャを無視し、テストを一緒に投げてそれらを通過させるのであれば、建物にとどまることを可能にするものを破壊することになりますシステムの構造と、システムの構造的完全性を維持するのに役立つ堅実な設計上の決定。

http://s3.amazonaws.com/hanselminutes/hanselminutes_0171.pdf、ページ4

構造設計を検証するという観点からTDDにアプローチする方が賢明だと思います。テストしなかった場合、デザインが正しくないことをどのように確認しますか?また、元のテストも変更せずに、変更が正しいことをどのように確認しますか?

ソフトウェアは、変更される可能性があるため、「ソフト」です。変更のに不安がある場合は、引き続きアーキテクチャ設計の経験を積んでください。アプリケーションアーキテクチャに加える必要のある変更の数は、時間の経過とともに減少します。


問題は、「賢明な計画」でさえ、あなたはそれの多くが変わると予想しています。私は通常、初期アーキテクチャの約80%をそのままにして、その間にいくつかの変更を加えます。これらの20%が私を悩ませています。
ヴィタウタスマッコニス

2
それこそがソフトウェア開発の性質だと思います。最初の試行でアーキテクチャ全体を正しく取得することは期待できません。
ロバートハーベイ

2
+1であり、TDDに反するものではありません。TDDは、コードの記述を開始したとき、正確には設計が終了したときに始まります。TDDは、設計で見落としたことを確認するのに役立ち、設計と実装をリファクタリングして続行できます。
スティーブンエバーズ

2
実際、ボブによれば(そして私も心から同感しています)、コードを書くこともデザインです。高レベルのアーキテクチャを持つことは間違いなく必要ですが、コードを書いても設計は終わりません。
マイケルブラウン

頭に釘を打つ本当に良い答え。TDDの賛否両論の多くの人々は、実際には古いデザインの狂気の滝に対する攻撃であるときに、「まったくデザインしないで、コーディングするだけ」として「大きなデザインなし」と考えているようです。設計は常に良い時間投資であり、重要なプロジェクトを成功させるために重要です。
サラ

3

TDDを行う場合。テストによって駆動されない限り、署名と動作を変更することはできません。したがって、失敗した30のテストは、プロセスで削除されるか、コードとともに変更/リファクタリングされました。または、それらは廃止され、削除しても安全です。

赤緑リファクタリングサイクルで赤を30回無視することはできませんか?

テストは、運用コードと一緒にリファクタリングする必要があります。余裕がある場合は、各変更後にすべてのテストを再実行します。

TDDテストを削除することを恐れないでください。一部のテストでは、目的の結果を得るためにビルディングブロックをテストします。機能レベルでの望ましい結果が重要です。選択/発明したアルゴリズムの中間ステップに関するテストは、結果に到達する方法が複数ある場合、または最初に行き止まりになった場合、あまり価値がない場合もあります。

いくつかの適切な統合テストを作成し、それらを保持し、残りを削除できる場合があります。それは、裏返しにするかトップダウンにするか、そしてどの程度のステップを踏むかによって多少異なります。


1

Robert Harveyがちょうど言ったように、おそらく、異なる概念ツール(つまり、「設計」または「モデリング」)で処理されるべきものにTDDを使用しようとしています。

システムを非常に抽象的な(「一般」、「あいまい」)方法で設計(または「モデル」)してみてください。たとえば、車をモデル化する必要がある場合は、startEngine()やint seatsなどの曖昧なメソッドとフィールドを持つ車クラスを用意します。つまり、どのように実装したいかではなく、公開したいものを記述します。基本的な機能(読み取り、書き込み、開始、停止など)だけを公開し、クライアントコードをその上に残してください(prepareMyScene()、killTheEnemy()など)。

この単純なパブリックインターフェイスを想定したテストを書き留めます。

必要に応じて、クラスとメソッドの内部動作を変更します。

パブリックインターフェイスとテストスイートを変更する必要がある場合は、やめてください。ほとんどの場合、これはAPIおよび設計/モデリングに何らかの問題があることを示しています。

APIを変更することは珍しいことではありません。1.0バージョンのほとんどのシステムは、APIの変更の可能性についてプログラマ/ユーザーに明示的に警告します。それにもかかわらず、APIの変更の制御されていない継続的なフローは、悪い(または完全に欠落した)デザインの明らかな兆候です。

ところで:通常、メソッドごとにほんの一握りのテストが必要です。メソッドは、定義により、ある種のデータに対して明確に定義された「アクション」を実装する必要があります。完全な世界では、これは単一のテストに対応する単一のアクションでなければなりません。現実の世界では、同じアクションの異なる「バージョン」がほとんどなく、対応する異なるテストがほとんどないことは珍しいことではありません。確かに、同じメソッドで30のテストを行うことは避けてください。これは、メソッドがあまりにも多くのことを行おうとしていることを示す明確な兆候です(そしてその内部コードは制御不能になります)。


0

ユーザーの観点から見ます。たとえば、APIを使用して名前と年齢のPersonオブジェクトを作成できる場合、名前と年齢のPerson(string name、int age)コンストラクターとアクセサーメソッドが必要です。名前と年齢の有無に関係なく、新しいPersonsのテストケースを作成するのは簡単です。

ダグ

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.