TDD、新しいテストと古いテストはまだ実装されていません


13

私はテスト駆動開発を実験していますが、次のような状況に陥ることが多いことがわかりました。

  1. 一部の機能Xのテストを作成します。これらのテストは失敗します。
  2. Xを実装しようとしているときに、コードの下位層に機能Yを実装する必要があることがわかりました。そう...
  3. Yのテストを作成します。XとYの両方のテストが失敗します。

一度に異なるコードレイヤーで4つの機能を同時に使用すると、実際に実行していることに集中できなくなりました(同時に失敗するテストが多すぎます)。

テストの作成を開始する前であっても、タスクの計画にもっと力を入れることでこれを解決できると思います。しかし、いくつかのケースでは、例えば、下層のAPIをあまりよく知らなかったので、もっと深くする必要があることを知りませんでした。

そのような場合はどうすればよいですか?TDDには推​​奨事項がありますか?

回答:


9

良い点は、テスト対象のコードに支援が必要であることを認識していることです。すぐに実装するのではなく、インターフェイスを作成し、モックを使用して、テストが正しいコードを調整していることを確認してください。これらのテストに合格すると、依存するコードの実装に進むことができます。


私のテストは通常​​、メソッドが内部的に何をすべきかについての知識を持っていません(どの低レベルAPIを呼び出すべきかについて)。テストしたコードで必要なものを模擬するようにテストを調整する必要がありますか?
リオリ

2
同様に、テストしたクラスは「下位層」が何をするかを気にするべきではありません。実際のクラス/オブジェクトの代わりにモック/スタブを使用します。これには、設計にもう少し手間がかかる場合がありますが、コードの結合が少なくなり、再利用しやすくなります。
-Mchl

1
依存性注入を使用していますか?これにより、低レベルの懸念を高レベルのクラスから簡単に分離できます。テスト対象のクラスには、インターフェイスのモックを作成するテストで(インターフェイスとして)依存関係のパラメーターを持つコンストラクターがあります。基本的に、低レベルのサービスを既に実装しているふりをしています。
マイケルブラウン

@マイク・ブラウン、はい、そうです。モックオブジェクトを作成できることは知っています。しかし、機能のテストでXは、依存関係のどの部分Xをモックする必要があるかを知る必要があります。これは実装の詳細の一部であり、テストの一部であってはなりません。そうでない場合は、実装のリファクタリング中にテストを変更する必要があるかもしれません。心配する必要がありますか?
リオリ

1
まったくありません...テストは、テスト対象のシステムの仮定を反映する必要があります。また、システムが依存するサービスから必要なものを公開するのにも役立ちます。私はこの問題に関して以前は同意していましたが、再帰プログラミングを理解するようになった方法と比較します。まず、必要なことを行う関数があると仮定してコードを記述します。次に、必要な処理を行うコードを記述します。
マイケルブラウン

4

スタブとモックを使用して、まだ変更/実装されていない機能をシミュレートできます。また、この種の「連鎖反応」を引き起こす依存関係を解決するのにも役立ちます。

一方、次の変更を実行する(失敗した)テストを1つだけ保持するのが最善の方法かもしれません。

新しい機能に依存するコードを対象とする他のテストは、この時点では実際には関連がないため、一時的に無効にすることができます。あなたの場合、Yなどを実装するまでXのテストを無効にします

そうすることで、次の変更にのみ集中することができます。


ハ、私はIDE内でのテスト実行中にテストをオフにする機能を探しましたが、見つかりませんでした。今、私はpythonのunittestテストスキップが既にあることがわかりました。これで十分かもしれません。
リオリ

GoogleテストC ++フレームワークを使用します。テストを無効にするオプションがあります。障害者のテストが実行されますがコンパイルされません-あなたがそれらを必要とする瞬間-彼らは実行する準備ができてあります(また、あなたが無効のテストの「力の実行」することができます-一種の「実行時有効」) -優れた機能...
ratkok

3

やめる

ちなみに、ここには2つの個別の問題があるように見えます。

  1. いくつかのストーリーとテストシナリオを忘れ、特定のテストシナリオで作業を開始するまでそれらを発見しなかった、および/または

  2. TDD 機能テストではなく、実際にユニットテストを行っています

#1の場合、停止し、戻って、ストーリーとテストシナリオを更新してから、別のシナリオでやり直します。

#2の場合、停止、ユニットではなく機能をテストしていることを忘れないでください。そのため、モックを使用して他のインターフェイスをグロスしたり、新しいテストシナリオ追加せずにテストをパスするコードを実装したりします。これは、テストシナリオが欠落していないことを前提としていますが、代わりに-これが実際に一般的である-単体テストとTDDを融合しています。


私はあなたの答えが本当に好きです、それは本当に何が起こっているかを説明するのにより良い仕事をします。
maple_shaft

...と言われても、「ストップ、我々はバックトラックする必要がある」というフレーズで完全に彼/彼女の心を失うことのない世界のPMを知りません。彼らは、プロジェクトを前進させ続けるために、祭壇で最初に生まれた人を犠牲にする以外のすべてを試して、技術的な負債と不完全な単体テストを非難します。組織での唯一のメトリックがプロジェクトを時間通りに完了している場合、それらを責めることはできないと思います。一部の組織は品質よりも時間を重視しているため、これらのタイプの組織でTDDが正常に機能するのを目にしたことはおそらくありません。
maple_shaft

@maple_shaft:再グループ化のために停止する時間はほんの数時間かもしれません-あなたのプロセスが方法でない限り、ベースから離れて、その場合、トラックに戻すために数日間停止することははるかに可能性が高くなりますプロジェクトは成功します。間違った道を進んで行くことに意味はありません!
スティーブンA.ロウ

0

これはTDDにとっても大きな疑問であり、大きな不満でもあります。このシナリオでは、開発を開始するまでに必要な下位レベルのコンポーネントまたは機能を知る方法がまったくないTDDが不足しているように感じます。

個人的に、TDDは、機能を実行するために何をする必要があり、何を呼び出す必要があるかを正確に知っている場合にのみ機能することがわかりました。開発者は始める前にすべてを常に知っているわけではないので、あなたが説明するまさにその状況を緩和するための自分にとっての最良の方法であることがわかりました。

プロトタイプ

簡単なプロトタイプアプリを作成して、技術的な問題への方法とアプローチを探求し、発見すると、多くの脚の仕事を発見し、その研究を開始する前に邪魔にならないようにします。設計と見積もりも同様に簡単になります。

プロトタイプが非常に複雑であるためにアプリケーションになる場合は、怠thingなことはせず、事実の後にプロトタイプの単体テストを作成することをお勧めします。

その時点で低レベルAPIについて詳しく知り、高レベルコンポーネントで低レベルAPIを正常にモックできるようにする必要があります。


したがって、実際には、非公式の(=形式化された方法論ではなく)探索的コーディングを実行することにより、計画フェーズの詳細情報を取得することを提案しています。そして、実際のコードを計画するのに十分な情報を提供すると仮定します。私は正しいですか?
リオリ

なぜプロトタイピングは非公式のプロセスだと思いますか?見積りごとにプロトタイピングを考慮し、プロジェクトスケジュールで必要な開発タスクを考慮する必要があります。私はそれをデザインやコードレビューと同じように見ています。そのメモでは、それは形式化されており、多くの未知のタスクについてさらに説明する必要があります。プロトタイピングと概念実証を実行する機能がなければ、TDDを追求することは、開発者がすべての機能を備えたあらゆるものを知っていることを前提としています。現実の世界はそのようには機能せず、私はあなたがどれほど賢いか経験豊富であるかを気にしません。
maple_shaft

「非公式の方法」とは、プロトタイピングの時間を考慮すべきではないという意味ではありませんが、プロトタイプを作成している間は、TDDやその他のコード方法論に従わないということです。
リオリ

TDDは、単体テストと開発のための方法論です。コードレビューのためにTDDを行うのは理にかなっていますか?TDDは、設計、技術仕様の作成、またはホワイトボードに意味がありますか?プロトタイピングはそれ自体が課題であり、研究、概念実証、および教育のための探索的な開発です。
maple_shaft

1
TDDはプロトタイピングに最適です。これにより、何でも(オブジェクト、関数、API、プログラム全体)を、反復可能な実行可能な一連の要件の形ですばやく公開できます。自分に賛成して、テストに導かれた成長オブジェクト指向ソフトウェアを読んでください。テストファースト方式でアプリケーション全体(統合を含む)を構築する手順を段階的に示します。
フランクシェラー

0

それは、TDDを行っている間にどのようなテストを書くかによって異なります。

古典的なモデルは、単体テストを記述し、モックまたはスタブを使用して、テストをコードの他の「ユニット」から切り離します。

ATDDなど、フルスタックテストまたはほぼフルスタックテストを行う代替モデルが他にも多数あります。この特定のケースでは、必要なプログラムの動作を1つのコード単位ではなくアサートするテストを書くので、他のテストを書くことはありません。テストを満たすために、ラウンドトリップを実装します。次に、他の機能/動作のために他のテストを追加します。

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