web-dev-qa-db-ja.com

TDDの使用時に機能または機能を削除する方法

TDDに関するテキストでは、リファクタリングの段階で「重複の削除」または「読みやすさの向上」についてよく読みました。しかし、未使用の関数を削除する理由は何ですか?

たとえば、メソッドa()およびb()を持つクラスCがあるとします。 Cに駆動されるメソッドf()があればいいと思います。実際、f()は、b()を定義/記述した単体テストを除いて、b()へのすべての呼び出しを置き換えます。テストを除いて、もう必要ありません。

b()とそれを使用したすべてのテストを削除するだけで済みますか?それは「読みやすさの向上」の一部ですか?

20
TobiMcNamobi

はい、もちろん。最も読みやすいコードは、そこにないコードです。

とは言っても、リファクタリングとは通常、動作を変更せずにコードを改善することを意味します。コードを改善する何かを考えたら、それを実行してください。あなたがそれをすることが許される前にそれをいくつかの鳩の穴に合わせる必要はありません。

16
Sebastian Redl

パブリックメソッドを削除することは「リファクタリング」ではありません。リファクタリングは、既存のテストに合格し続けながら実装を変更することです。

ただし、不要なメソッドを削除することは、完全に合理的な設計変更です。

TDDはこれをある程度引き出します。テストを見直すと、不要なメソッドをテストしていることがわかるでしょう。 「見て、このテストは私の目標とは何の関係もない」ということができるので、テストは設計を推進しています。

コードカバレッジツールと組み合わせて、より高いレベルのテストでさらに明らかになる可能性があります。コードカバレッジを使用して統合テストを実行し、メソッドが呼び出されていないことを確認した場合、それはメソッドが使用されていないことの手掛かりです。静的コード分析は、メソッドが使用されていないことを示すこともあります。

メソッドを削除するには2つの方法があります。どちらも異なる状況で機能します。

  1. メソッドを削除します。コンパイルエラーに従って、依存するコードとテストを削除します。影響を受けるテストが使い捨てであることに満足したら、変更をコミットします。そうでない場合は、ロールバックします。

  2. 古くなったと思われるテストを削除します。コードカバレッジを使用してテストスイート全体を実行します。テストスイートで実行されていないメソッドを削除します。

(これは、テストスイートが最初から十分にカバーされていることを前提としています)。

27
slim

実際にf()は、b =)を定義/説明した単体テストを除いて、b()へのすべての呼び出しを置き換えます

典型的なTDDサイクルは次のようになります。

  • f()の失敗したテストを記述します(おそらくb()のテストに基づいています):tests go red

  • 実装f()->テストはgreenになります

  • リファクタリング:->削除b()およびb()のすべてのテスト

最後のステップについては、まずb()を削除して何が起こるかを確認することを検討してください(コンパイル済み言語を使用する場合、コンパイラーは既存のテストについてのみ文句を言うべきです。 bのテストは失敗するため、それらも削除する必要があることは明らかです)。

10
Doc Brown

はい、そうです。

最良の、最もバグのない、最も読みやすいコードは、存在しないコードです。要件を満たしながら、できるだけ多くの非コードを書くように努めてください。

4
Kilian Foth

最初に未使用の関数を追加しないことが望ましいのと同じ理由で、使用されなくなったらb()を削除することが望ましいです。それを「可読性」と呼ぶか、他の何かと呼ぶかに関わらず、他のすべてが等しい場合、それはそれが役に立たないものを何も含まないというコードの改善です。それを持たない方が良い特定の方法を少なくとも1つ持つために、それを削除すると、変更後の将来のメンテナンスコストがゼロになることが保証されます。

実際にb()を新しいものに置き換えるという考えには、もちろんb()、およびテストは「すべてのコード」のサブセットです。

私にとって一般的に機能する推論の行は、f()b()を廃止したことに気づいた時点で、したがってb()は少なくとも非推奨であるべきです。 b()への呼び出しで置き換えるために、f()へのすべての呼び出しを見つけようとしていますテストコードも考慮しています。具体的には、b()が不要になった場合、単体テストを削除できます。

あなたはまったく正しいですforcesb()が不要になったことに気づきました。それはスキルの問題です(そして、細かく言うと、コードカバレッジはより高いレベルのテストを報告します)。単体テストのみで機能テストがない場合は、b()を参照してください。これは、公開されたインターフェイスの一部ではないため、慎重に楽観的にすることができます。コントロール。

赤/緑/リファクタリングのサイクルでは、テストの削除について明示的に言及されていません。さらに、b()を削除すると、コンポーネントisが変更のために明らかに開いているため、開閉の原則に違反します。したがって、このステップを単純なTDDの外の何かと考えたい場合は、先に進んでください。たとえば、テストを「悪い」と宣言するためのプロセスがある場合があります。このプロセスを適用して、存在すべきではないものをテストするという理由でテストを削除できます(不要な関数b())。

実際には、ほとんどの人はおそらく、赤、緑、リファクタリングのサイクルに沿ってある程度の再設計を実行することを許可するか、厳密に言えば、冗長ユニットテストを「リファクタリング」の有効な部分として削除することを検討しますリファクタリングではありません。チームは、この決定の正当化に関与する必要のあるドラマと書類の量を決定できます。

とにかく、b()が重要である場合は、その機能テストがあり、それらは簡単には削除されませんが、単体テストしかないとすでに述べました。 (変更したコードの現在の内部設計に書き込まれた)単体テストと(おそらく変更したくない、公開されたインターフェースに書き込まれた)機能テストを適切に区別しない場合は、さらに注意する必要があります。単体テストの削除について。

2
Steve Jessop

常に覚えておくべきことの1つは、バージョンコントロールでコードリポジトリを使用していることです。削除されたコードは実際にはなくなっていません...それは前の反復のどこかにまだ残っています。吹き飛ばせ!いつでも戻って、いつか役に立つかもしれないと思っていた貴重なエレガントなメソッドをいつでも取得できるので、削除キーを自由に使用してください。それはそこにあります。

もちろん、これは下位互換性のないリリースの問題と危険性の警告に沿っています...インターフェイスの実装に依存していた外部アプリケーションは、(突然)非推奨のコードによって孤立します。

2
dwoz