単体テストを既存の本番プロジェクトに追加できますか?もしそうなら、どのように、そしてそれは価値がありますか?


140

運用中の既存のプロジェクトに単体テストを追加することを強く検討しています。TDD (フェイスパーム)のメリットが実際に見られるようになる前に18か月前に開始されたので、これは多くのプロジェクトを含むかなり大きなソリューションであり、単体テストの追加をどこから始めればよいかわかりません。私がこれを考慮しているのは、時々古いバグが再浮上しているように見える、またはバグが実際には修正されずに修正済みとしてチェックインされることです。単体テストは、これらの問題の発生を軽減または防止します。

SOで同様の質問を読むことで、バグトラッカーから始めて、各バグのテストケースを作成してリグレッションを防ぐなどの推奨事項を見てきました。ただし、全体像を見逃してしまい、最初からTDDを使用した場合に含まれていたはずの基本的なテストを見落としてしまうのではないかと心配しています。

既存のソリューションが適切に単体テストされ、ただ組み込まれているだけではないことを確認するために、順守すべきプロセス/ステップはありますか?どのように私はテストが良い品質のものであり、念のないことを確認することができます任意のテストの無いテストよりも優れています

だから私も私が求めているのは何かだと思います。

  • 運用中の既存のソリューションに取り組む価値はありますか?
  • このプロジェクトのテストを無視し、将来の可能性のある書き換えで追加する方が良いでしょうか?
  • より有益になるもの; 数週間かけてテストを追加したり、数週間かけて機能を追加したりしますか?

(明らかに、3番目のポイントに対する答えは、管理者と開発者のどちらに話しているかに完全に依存します)


バウンティの理由

奨励金を追加して、幅広い回答を引き付け、それが良いことであるという私の既存の疑いを確認するだけでなく、それに対するいくつかの正当な理由も確認します。

この質問を長所と短所で後で書き、製品の将来の開発をTDDに移行するのに何時間も費やす価値があることを経営者に示すことを目指しています。私はこの課題に取り組み、自分自身の偏見のない視点で私の推論を展開したいと思います。


11
:話題のマイケル羽の本に必須のリンクamazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/...
マークRushakoff

1
@Mark-ありがとう、私が提供したリンクにあります。私は別の本を購入せずにまともな答えを得ることを望んでいました...(あなたがそうしたい仕事をやりたいと思わない限り)あなたはあまり多くの本を持つことはできませんが。
djdd87 2010

1
あなたは本当にこの本を読む必要があります:)これは私のお気に入りの1つであり、リファクタリングと自動テストの間の緊張を理解するのに本当に役立ちます。
manuel aldana

回答:


177

以前はそれがなかったコードベースにユニットテストを導入しました。私がこれに携わった最後の大きなプロジェクトで、チームに到着したとき、製品はすでにユニットテストなしで生産されていました。私が去ったとき-2年後-4500以上のテストが行​​われ、230 000以上の生産LOC(リアルタイムの金融Win-Formsアプリケーション)のコードベースで約33%のコードカバレッジが得られました。低く聞こえるかもしれませんが、その結果、コードの品質と欠陥率が大幅に向上し、さらに士気と収益性も向上しました。

これは、関係者からの正確な理解とコミットメントの両方がある場合に実行できます。

まず、単体テストはそれ自体がスキルであることを理解することが重要です。「従来の」標準によって非常に生産性の高いプログラマでありながら、大規模なプロジェクトで拡張できる方法で単体テストを作成するのに苦労する場合があります。

また、特にあなたの状況では、テストのない既存のコードベースに単体テストを追加することも、それ自体が専門的なスキルです。あなたやあなたのチームの誰かがユニットコードを既存のコードベースに導入することに成功した経験がない限り、Featherの本を読むことは必須です(オプションではなく、強くお勧めしません)。

コードの単体テストへの移行は、コードベースの品質と同じくらいの人とスキルへの投資です。これを理解することは、考え方や期待を管理する上で非常に重要です。

今、あなたのコメントと質問のために:

ただし、全体像を見逃してしまい、最初からTDDを使用した場合に含まれていたはずの基本的なテストを見落としてしまうのではないかと心配しています。

短い答え:はい、あなたはテストを逃します、そしてはい、彼らは最初にグリーンフィールドの状況で彼らがするであろうもののように見えないかもしれません。

より深いレベルの答えはこれです:それは問題ではありません。テストなしで開始します。テストの追加を開始し、必要に応じてリファクタリングします。スキルレベルが向上したら、プロジェクトに追加されたすべての新しく記述されたコードの基準を引き上げ始めます。等を改善していきます...

さて、ここの行間を読んでいると、これは「行動を起こさない言い訳としての完璧」という考え方から来ているという印象を受けます。より良い考え方は、自己信頼に焦点を当てることです。まだ方法がわからない場合があるので、空欄に記入する方法を理解します。したがって、心配する必要はありません。

繰り返しますが、そのスキル。1つの「プロセス」または「ステップバイステップ」のクックブックアプローチで線形テストの方法でゼロテストからTDD完全に移行することはできません。プロセスになります。あなたの期待は、漸進的かつ漸進的な進歩と改善をすることでなければなりません。魔法の薬はありません。

良いニュースは、数か月(場合によっては数年)が経過するにつれて、コードが徐々に適切に因数分解され、十分にテストされた「適切な」コードになることです。

補足として。古いコードベースでユニットテストを導入する際の主な障害は、結束の欠如と過度の依存関係であることがわかります。したがって、最も重要なスキルは、実際の単体テスト自体を作成するのではなく、既存の依存関係を切り離してコードを分離する方法になることでしょう。

既存のソリューションが適切に単体テストされており、単に組み込まれているだけではないことを保証するために、遵守すべきプロセス/ステップはありますか?

すでにそれがない場合は、ビルドサーバーをセットアップし、コードカバレッジ付きのすべての単体テストを含むすべてのチェックインで実行される継続的インテグレーションビルドをセットアップします。

あなたの人々を訓練します。

どこかから始めて、顧客の視点から進歩を遂げている間にテストを追加し始めます(以下を参照)。

コードカバレッジは、プロダクションコードベースのどの程度がテストされているかのガイドリファレンスとして使用します。

ビルド時間は常に高速である必要があります。ビルド時間が遅い場合、単体テストのスキルが遅れています。遅いテストを見つけて改善します(本番用コードを分離して個別にテストします)。よく書かれているので、数千の単体テストを簡単に実行でき、10分未満でビルドを完了することができます(1〜数ms /テストは良いですが、非常に大まかなガイドラインです。リフレクションを使用するコードなどのいくつかの例外が適用される場合があります) )。

検査して適応します。

テストが高品質であり、テストのケースだけではないことをどのようにして確認できるかをテストなしよりも優れています。

あなた自身の判断があなたの現実の第一の情報源でなければなりません。スキルを置き換えることができる指標はありません。

その経験や判断力がない場合は、そうした人と契約することを検討してください。

2つの大まかな二次的な指標は、合計コードカバレッジとビルド速度です。

運用中の既存のソリューションに取り組む価値はありますか?

はい。カスタムビルドのシステムまたはソリューションに費やされる費用の大部分は、本稼働に投入された後に費やされます。また、品質、人、スキルへの投資は時代遅れにならないようにしてください。

このプロジェクトのテストを無視し、将来の可能性のある書き換えで追加する方が良いでしょうか?

人とスキルへの投資だけでなく、最も重要なことには、システムの総所有コストと予想される寿命を考慮する必要があります。

私の個人的な答えは、大抵の場合「はい」です。私はそれが非常に良いことを知っているためですが、例外があるかもしれないことを認識しています。

より有益になるもの; 数週間かけてテストを追加したり、数週間かけて機能を追加したりしますか?

どちらでもない。あなたのアプローチは、機能面で進歩している間、コードベースにテストを追加することです。

繰り返しになりますが、これは人、スキル、およびコードベースの品質への投資であり、そのため時間もかかります。チームメンバーは、依存関係を破る方法、単体テストを書く方法、新しいハビッツを学ぶ方法、規律と品質の認識を向上させる方法、ソフトウェアをより適切に設計する方法などを学ぶ必要があります。これらのスキルはまだ、そのアプローチを成功させるために必要なレベルにあるため、多くのテストを追加するためにすべての時間を費やすために進行を止めることは、単に機能しません。

また、任意のサイズのプロジェクトサイズの既存のコードベースに単体テストを追加することは、コミットメントと永続性を必要とする大きな作業です。基本的なものを変更することはできません。途中で多くの学習を期待し、ビジネス価値の流れを停止することでROIを期待しないようにスポンサーに依頼することはできません。それは飛ばないでしょうし、率直に言って飛べないはずです。

3つ目は、チームに健全なビジネスフォーカスの価値を浸透させることです。品質は顧客を犠牲にすることは決してなく、品質なしで速く行くことはできません。また、顧客は変化する世界に住んでいます。あなたの仕事は、顧客が適応しやすくすることです。顧客の調整には、品質とビジネス価値の流れの両方が必要です。

あなたがしていることは技術的な負債を返済することです。そして、常に変化するニーズに対応しながら、そうするのです。徐々に借金が返済されると状況が改善し、顧客により良いサービスを提供し、より多くの価値を提供することが容易になります。このポジティブな勢いは、持続可能なペースの原則を強調し、開発チーム、顧客、および利害関係者の両方にとってモラルを維持および改善するため、あなたが目指すべきものです。

それが役に立てば幸い


私と同じ考え方を反映しています。現在、私は、大規模なJAVAアプリケーションでテストケースを導入するためのこの正確なプロセス/メソッドを紹介しています。:)
Darshan Joshi 2015

3
これは、Stackoverflowでこれまでに読んだすべてのトピックについて、最も明確な回答です。よくやった!あなたがそうしていないなら、私はあなたに最後の質問へのあなたの答えについて本を書くことを検討することを勧めます。
Yermo Lamers 2017

ヤーモありがとうございます。本を書く時間があるかどうかわかりません。しかし、おそらく私はブログ記事を1つまたは2つ書くことができます。新しいブログを始めたばかりなので、しばらく時間がかかるかもしれません。
Mahol25、18年

2
この男のユニットテストのアドバイスは、一般的な人生のアドバイスです。真剣に。
Wjdavis5

24
  • 運用中の既存のソリューションに取り組む価値はありますか?

はい!

  • このプロジェクトのテストを無視し、将来の可能性のある書き換えで追加する方が良いでしょうか?

番号!

  • より有益になるもの; 数週間かけてテストを追加したり、数週間かけて機能を追加したりしますか?

テスト(特に自動テスト)を追加すると、それが作るくらい簡単に、将来的に取り組んでプロジェクトを保つために、それははるかに少ない可能性が高いユーザーに愚かな問題を出荷だろうということになります。

アプリオリに入れるテストとは、コード(およびその中の各モジュール)へのパブリックインターフェイスがあなたの考えているとおりに機能しているかどうかを確認するテストです。可能であれば、コードモジュールが持つ必要のある分離された各障害モードを誘導するようにしてください(これは重要なことであり、障害がどのように失敗するかをあまり注意深くチェックしないように注意してください)ログに記録されていることを確認するだけで十分なので、失敗時に生成されるログメッセージの数をカウントするなどの処理を実行します。

次に、バグを正確に誘発し、バグが修正されたときに合格する、バグデータベース内の現在のバグごとにテストを実行します。次に、それらのバグを修正します。:-)

テストを追加するための事前の時間はかかりますが、コードの品質がはるかに高くなるため、バックエンドで何度も返済されます。これは、新しいバージョンを出荷したり、メンテナンスを実行したりするときに非常に重要です。


精巧な対応をありがとう。私が感じていたことを確認しました。投票する前に、他にどのような回答が投稿されるかを確認し、承認します。
djdd87 2010

15

単体テストの改造の問題は、ここで依存関係を注入したり、そこでインターフェースを使用したりすることを考えていなかったことに気付き、まもなくコンポーネント全体を書き直すことになるでしょう。これを行う時間があれば、安全策を講じることができますが、途中で微妙なバグが発生する可能性があります。

私は最初から本当にユニットテストを必要とする多くのプロジェクトに関与してきましたが、コードを機能させてすでに収益を上げている場合は通常正当化できない完全な書き直しを除いて、それらを簡単に導入する方法はありません。最近、私は欠陥が発生するとすぐに欠陥を再現する方法でコードを実行するpowershellスクリプトを記述し、これらのスクリプトを一連の回帰テストとして保持して、将来の変更に備えています。そうすれば、アプリケーションのテストをあまり変更せずに構築し始めることができますが、これらは適切な単体テストというよりは、エンドツーエンドの回帰テストに似ています。


コードが最初からかなりうまく分割されている場合、それをテストするのはかなり簡単です。問題は、乱雑にすべてつなぎ合わされたコードがあり、公開されているテストポイントが完全な統合テストのみの場合です。(他のコンポーネントに依存してモックを作成するのは簡単ではないため、テスト可能性がほぼゼロのようなコードがあり、展開にはサーバーの再起動が必要です。テスト可能ですが、うまく実行できません。)
Donal Fellows

13

他のほとんどの人が言ったことに同意します。既存のコードにテストを追加することは価値があります。私はその点に決して反対しませんが、1つの警告を加えたいと思います。

既存のコードにテストを追加することは価値がありますが、コストがかかります。これは、新しい機能を構築しないという犠牲を伴います。これら2つがどのようにバランスをとるかは、プロジェクトに完全に依存し、いくつかの変数があります。

  • すべてのコードをテストするのにどのくらいかかりますか?日々?何週間?何ヶ月?何年?
  • 誰のためにこのコードを書いていますか?顧客に支払う?教授?オープンソースプロジェクト?
  • あなたのスケジュールはどうですか?あなたが満たさなければならない厳しい期限はありますか?締め切りはありますか?

繰り返しになりますが、テストは価値があり、古いコードをテストするように努力する必要があります。これは本当にあなたがそれに取り組む方法の問題です。すべてを削除して、古いコードをすべてテストする余裕がある場合は、実行してください。それが現実的でない場合は、少なくとも次のことを行ってください。

  • あなたが書くどんな新しいコードも完全にユニットテストの下にあるべきです
  • あなたがたまたま触れた古いコード(バグ修正、拡張など)は、単体テストの下に置かれるべきです

また、これはオールオアナッシングの命題ではありません。たとえば、4人のチームがいて、1人または2人にレガシーテストの義務を課すことにより、期限を守ることができる場合は、必ずそうしてください。

編集:

この質問を長所と短所で後で書き、製品の将来の開発をTDDに移行するのに何時間も費やす価値があることを経営者に示すことを目指しています。

これは、「ソース管理を使用することの長所と短所は何ですか?」または「採用前に面接することの長所と短所は何ですか?」または「呼吸の長所と短所は何ですか?」

時には、議論の片側だけがあります。 どんな複雑なプロジェクトでも、何らかの形で自動テストを行う必要があります。いいえ、テストはそれ自体を記述しません。そして、はい、物事をドアから出すのに少し余分な時間がかかります。しかし、長期的には、事前にテストを作成するよりも、事後のバグ修正に時間と費用がかかります。 限目。これですべてです。


9

テストを追加し始めたとき、それは10年前の約100万行のコードベースで、UIとレポートコードにロジックが多すぎました。

(継続的ビルドサーバーのセットアップ後に)最初に行った作業の1つは、回帰テストを追加することでした。これらはエンドツーエンドのテストでした。

  • 各テストスイートは、データベースを既知の状態に初期化することから始まります。実際には、Subversionに(膨大なサイズのため、コードとは別のリポジトリに)保持している何十もの回帰データセットがあります。各テストのFixtureSetUpは、これらの回帰データセットの1つを一時データベースにコピーし、そこから実行します。
  • 次に、テストフィクスチャのセットアップにより、結果に関心のあるプロセスが実行されます(この手順はオプションです。一部の回帰テストは、レポートをテストするためだけに存在します)。
  • 次に、各テストはレポートを実行し、レポートを.csvファイルに出力し、その.csvの内容を保存されたスナップショットと比較します。これらのスナップショット.csvは、各回帰データセットの横のSubversionに保存されます。レポートの出力が保存されたスナップショットと一致しない場合、テストは失敗します。

回帰テストの目的は、何かが変更されたかどうかを知らせることです。つまり、何かを壊した場合は失敗しますが、故意に何かを変更した場合も失敗します(この場合の修正は、スナップショットファイルを更新することです)。スナップショットファイルが正しいことさえわかりません。システムにバグがある可能性があります(これらのバグを修正すると、回帰テストは失敗します)。

それにもかかわらず、回帰テストは私たちにとって大きな勝利でした。私たちのシステムのほぼすべてにレポートがあります。そのため、レポートの周りにテストハーネスを配置するのに数週間を費やすことで、コードベースの大部分をある程度カバーすることができました。同等の単体テストを作成するには、数か月または数年かかります。(ユニットテストを使用すると、カバレッジが大幅に向上し、脆弱性もはるかに少なくなりますが、完璧になるまで何年も待つのではなく、今すぐ何かを使用します。)

次に戻って、バグを修正したり、機能拡張を追加したり、コードを理解する必要があるときに、単体テストの追加を開始しました。回帰テストはユニットテストの必要性を決して取り除くものではありません。これらは単なる第1レベルのセーフティネットであるため、ある程度のテスト範囲をすばやく取得できます。次に、リファクタリングを開始して依存関係を解消し、単体テストを追加できます。リグレッションテストは、リファクタリングが何も壊していないことをある程度確信させます。

回帰テストには問題があります。低速であり、失敗する理由は多すぎます。しかし、少なくとも私たちにとっては、彼らはそれだけの価値がありました。彼らは過去5年間で数え切れないほどのバグをキャッチしており、QAサイクルを待つのではなく、数時間以内にバグをキャッチしています。元の回帰テストはまだあり、7つの異なる継続的ビルドマシン(高速ユニットテストを実行するマシンとは別)にまたがっており、時々追加することさえあります。 +単体テストは対象外です。


8

それは絶対に価値があります。私たちのアプリには複雑な相互検証ルールがあり、最近、ビジネスルールに大幅な変更を加える必要がありました。ユーザーが保存できない競合が発生しました。アプリケーションでそれを整理するには永遠にかかることがわかりました(問題が発生した時点に到達するまでに数分かかります)。自動化された単体テストを導入してフレームワークをインストールしたかったのですが、正常に機能することを確認するために、いくつかのダミーテスト以外に何もしていませんでした。新しいビジネスルールを手に入れて、私はテストを書き始めました。テストによって競合の原因となった状態がすぐに特定され、ルールを明確にすることができました。

追加または変更する機能をカバーするテストを作成すると、すぐにメリットが得られます。書き直しを待つと、自動テストが行​​われなくなる可能性があります。

すでに機能している既存のもののテストを書くのに多くの時間を費やすべきではありません。ほとんどの場合、既存のコードの仕様がないため、テストしている主なものはリバースエンジニアリング能力です。一方、何かを変更する場合は、その機能をテストでカバーして、変更が正しく行われたことがわかるようにする必要があります。そしてもちろん、新しい機能については、失敗するテストを作成し、不足している機能を実装します。


6

私は自分の声を追加して「はい」と言います。それは常に役に立ちます!

ただし、留意すべきいくつかの違いがあります。ブラックボックスとホワイトボックス、ユニットと機能の違いです。定義が異なるので、これらは私が意味するものです:

  • ブラックボックス =実装に関する特別な知識なしで記述されたテスト。通常は、単純なユーザーが期待するとおりに動作することを確認するために、エッジケースを調べます。
  • ホワイトボックスが書かれているテスト= 、多くの場合、よく知られた故障箇所を行使しようとする実装の知識を、。
  • ユニットテスト =個々のユニット(機能、分離可能なモジュールなど)のテスト。たとえば、配列クラスが期待どおりに機能すること、および文字列比較関数が幅広い入力に対して期待される結果を返すことを確認します。
  • 機能テスト =システム全体を一度にテストします。これらのテストは、システムの大きな部分を一度に実行します。例:init、接続を開く、実際の操作を行う、閉じる、終了する。これらと単体テストの目的は異なるため、これらを区別したいのです。

ゲームの後半に出荷製品にテストを追加したところ、ホワイトボックステストと機能テストから最も費用対効果が高いことがわかりました。コードの一部が特に脆弱であることがわかっている場合は、ホワイトボックステストを記述して問題のケースをカバーし、同じ方法で2回中断しないことを確認してください。同様に、システム全体の機能テストは、最も一般的な10の使用事例を決して壊さないことを確認するのに役立つ有用な健全性チェックです。

小さなユニットのブラックボックステストとユニットテストも役立ちますが、時間が限られている場合は、早期に追加することをお勧めします。発送するまでに、これらのテストで発見されるであろうエッジケースと問題の大部分を(困難な方法で)発見しました。

他の人と同様に、TDDに関する2つの最も重要なことを思い出します。

  1. テストの作成は継続的な仕事です。止まることはありません。新しいコードを書くたびに新しいテストを追加するか、既存のコードを変更する必要があります。
  2. あなたのテストスイートは絶対に絶対です!テストがあるという事実が誤った安心感に落ち着かないようにしてください。テストスイートに合格したからといって、正常に機能している、または微妙なパフォーマンスの低下などが導入されていないということではありません。

4

運用中のアプリに単体テストを追加する価値があるかどうかは、アプリを維持するためのコストによって異なります。アプリにバグと機能強化のリクエストがほとんどない場合は、努力する価値はありません。OTOH、アプリにバグがあるか頻繁に変更される場合、単体テストは非常に有益です。

この時点で、ユニットテストを選択的に追加することについて話していることを思い出してください。最初からTDDを実践した場合に存在するようなテストスイートを生成しようとするのではありません。したがって、2番目の質問の後半に応じて、次のプロジェクトでTDDを使用するように注意してください。それが新しいプロジェクトであるか、書き直しであるか(申し訳ありませんが、実際に読む必要がある別の本へのリンクがあります) :テストによってガイドされる成長するオブジェクト指向ソフトウェア

3番目の質問に対する私の答えは最初の質問と同じです。それはプロジェクトのコンテキストに依存します。

あなたの投稿に埋め込まれているのは、レトロフィットされたテストが適切に行われることを保証することに関するさらなる質問です。確保するために重要なことは、そのユニットテストは実際にあるあるユニットの制御の反転を;テストを改造すると、あなたの層/コンポーネント(参照の依存性注入のデカップリングできるように、既存のコードをリファクタリングする必要があることのテスト、そしてこの(より頻繁ではない)手段スタブ。あざける)。これを強制できない場合、テストは統合テストになります。これは便利ですが、真の単体テストよりも対象が限定されず、より脆弱です。


4

実装言語については触れませんが、Javaの場合はこのアプローチを試すことができます。

  1. 別のソースツリーで、回帰テストまたは「煙」テストを作成し、ツールを使用してそれらを生成すると、80%のカバレッジに近づく可能性があります。これらのテストは、すべてのコードロジックパスを実行し、その時点から、コードは(バグが存在する場合でも)現在とまったく同じように動作することを確認します。これにより、手作業でコードを簡単にユニットテストできるようにするために必要なリファクタリングを実行するときに、不注意で動作が変化することに対する安全策が得られます。

  2. 修正するバグ、または今後追加する機能ごとに、TDDアプローチを使用して、新しいコードがテスト可能に設計されていることを確認し、これらのテストを通常のテストソースツリーに配置します。

  3. また、既存のコードは、新しい機能を追加する一環としてテスト可能にするために、おそらく変更またはリファクタリングする必要があります。あなたの煙のテストはあなたに行動への退行や不注意による微妙な変化に対する安全策を与えます。

  4. TDDを介して変更(バグ修正または機能)を行う場合、完了すると、コンパニオンスモークテストが失敗する可能性があります。手書きの単体テストはその改善されたコンポーネントを完全にカバーしているため、変更が原因で失敗が予想どおりであることを確認し、判読しにくい煙テストを削除します。テストカバレッジが減少しないか、変化しないか増加するかを確認します。

  5. バグを修正するときは、最初にバグを公開する失敗する単体テストを記述します。


3

ユニットテストは、バグが本番環境に侵入する前に阻止するのに役立つため、ユニットテストは非常に重要であると言って、この回答を始めたいと思います。

バグが再導入されたプロジェクト/モジュールの領域を特定します。テストを作成するプロジェクトから始めます。新しい機能とバグ修正のためのテストを書くことは完全に理にかなっています。

運用中の既存のソリューションに取り組む価値はありますか?

はい。バグの影響がわかり、メンテナンスが容易になる

このプロジェクトのテストを無視し、将来の可能性のある書き換えで追加する方が良いでしょうか?

今から始めたらオススメです。

より有益になるもの; 数週間かけてテストを追加したり、数週間かけて機能を追加したりしますか?

あなたは間違った質問をしています。確かに、機能性は何よりも重要です。しかし、テストを追加するために数週間を費やすことで、私のシステムがより安定するかどうかを尋ねるべきです。これはエンドユーザーに役立ちますか?チームの新しい開発者がプロ​​ジェクトを理解し、変更の全体的な影響を理解していないために開発者がバグを発生させないようにするのに役立ちますか。


3

私は、リファクタリングをどこから始めればよいかという質問への答えとして、ぶら下がっている果物リファクタリングするのがとても好きです。これは、かみ砕ける以上の量を食い込ませることなく、より良い設計を容易にする方法です。

TDDにも同じロジックが適用されると思います-または単体テスト:必要に応じて、必要なテストを記述してください。新しいコードのテストを書く。バグが現れるたびにテストを記述します。コードベースの到達が難しい領域を無視することを心配しています。これは確かにリスクですが、開始する方法として:始めましょう!コードカバレッジツールを使用すると、将来のリスクを軽減できます。リスクは(私の意見では)それほど大きくありません。バグをカバーしている場合、新しいコードをカバーしている場合、見ているコードをカバーしている場合では、テストが最も必要なコードをカバーします。


2
  • はい、そうです。新しい機能を追加し始めると、古いコードが変更される可能性があり、その結果、潜在的なバグの原因となります。
  • (最初のものを参照)新しい機能を追加する前に、すべての(またはほぼ)コードを(理想的には)単体テストでカバーする必要があります。
  • (最初と2番目のものを参照してください):)。新しい壮大な機能により、古いコードを「破壊」することができます。

2

はい、できます。今から作成するすべてのコードにテストが実施されていることを確認してください。

すでに配置されているコードを変更する必要があり、テストできる場合は、そのようにします。ただし、安定したコードのテストを実行しようとすることに、あまり力を入れすぎない方がよいでしょう。そのようなことは、ノックオン効果をもたらす傾向があり、制御不能になってしまいます。


2

運用中の既存のソリューションに取り組む価値はありますか?
はい。ただし、開始するためにすべての単体テストを記述する必要はありません。1つずつ追加してください。

このプロジェクトのテストを無視し、将来の可能性のある書き換えで追加する方が良いでしょうか?
いいえ。機能を壊すコードを初めて追加するときは、後悔します。

より有益になるもの; 数週間かけてテストを追加したり、数週間かけて機能を追加したりしますか?
新しい機能(コード)の場合は簡単です。最初に単体テストを記述してから、機能を記述します。古いコードについては、方法を決定します。すべてのユニットテストを実施する必要はありません...最も害を与えていないものを追加してください...時間(およびエラー)によって、どのテストに集中する必要があるかがわかります;)


2

更新

元の回答から6年後、私は少し異なる見解を持っています。

作成したすべての新しいコードに単体テストを追加し、変更を加えた場所をリファクタリングしてテスト可能にするのは理にかなっていると思います。

既存のすべてのコードに対して一度にテストを作成しても効果はありませんが、作成した新しいコード(または変更した領域)のテストを作成しないことも意味がありません。リファクタリング/追加時にテストを追加することは、テストを追加し、テストのない既存のプロジェクトでコードをより保守しやすくするためのおそらく最良の方法です。

以前の答え

私はここにいくつかの眉毛を上げるつもりです:)

まず第一にあなたのプロジェクトは何ですか?それがコンパイラ、言語、フレームワーク、または機能的に長期間変化しないものなら、ユニットテストを追加することは絶対に素晴らしいと思います。

ただし、(要件の変更により)機能の変更が必要になる可能性のあるアプリケーションで作業している場合は、その追加の作業を行う意味はありません。

どうして?

  1. 単体テストはコードテストのみをカバーします-コードが設計どおりに機能するかどうか-それはとにかく実行する必要がある手動テストの代わりではありません(機能のバグ、使いやすさの問題、その他すべての種類の問題を明らかにするため)

  2. 単体テストには時間がかかります!私の出身地は今や貴重な商品です。ビジネスでは通常、完全なテストスイートよりも優れた機能を採用しています。

  3. アプリケーションがユーザーにとってリモートで役立つ場合でも、ユーザーは変更を要求します。つまり、より適切に、より速く、そしておそらく新しいことを実行するバージョンが作成されます。コードが大きくなるにつれて、多くのリファクタリングも行われる可能性があります。動的環境で完全に成長した単体テストスイートを維持することは頭痛の種です。

  4. 単体テストは、製品の知覚品質(ユーザーに表示される品質)に影響を与えません。確かに、メソッドは1日目とまったく同じように機能する可能性があります。プレゼンテーションレイヤーとビジネスレイヤーの間のインターフェイスは元の状態のままかもしれませんが、どうでしょうか。ユーザーは気にしません!実際のテスターに​​アプリケーションをテストしてもらいます。そして、たいていの場合、これらのメソッドとインターフェースは、いずれにせよ、遅かれ早かれ変更する必要があります。

より有益になるもの; 数週間かけてテストを追加したり、数週間かけて機能を追加したりしますか?-テストを作成するよりも多くのことができることはたくさんあります-新しい機能を作成し、パフォーマンスを向上させ、使いやすさを向上させ、ヘルプマニュアルを作成し、保留中のバグを解決するなどします。

今私を誤解しないでください-今後100年間変わらないと確信しているなら、先に進んで、自分をノックアウトして、それらのテストを書いてください。自動テストはAPIにとっても優れたアイデアであり、サードパーティのコードを絶対に壊したくない。他のどこにでも、それは私を後で出荷させるものです!


そして、これを読むことをお勧めします -joelonsoftware.com/items/2009/01/31.html
Roopesh Shenoy

「保留中のバグを修正」しますか、それとも発生しないようにしますか?適切な単体テストは、バグ修正に費やす時間を最小限に抑えることで時間を節約します。
Ihor Kaharlichenko 2010

それは神話です。自動化された単体テストは手動テストの代わりになると私に言っているのなら、あなたは深刻に、深刻に誤解されています。バグではない場合、手動テスターは何をログに記録しますか?
Roopesh Shenoy 2010

そして、ええ、私を誤解しないでください-単体テストは絶対的な無駄だと言っているわけではありません-重要なのは、テストを書くのにかかる時間と、製品を変更したときに変更する必要がある理由を考慮して、実際に見返りがあるかどうかです。私にとっては、私は両方を試してみましたが、答えはノーでした、彼らは十分に早く返済しません。
Roopesh Shenoy、2010

1

テストのカバレッジが大幅に増える可能性は低いため、テストを追加する場所について戦術的である必要があります。

  • おっしゃったように、バグを見つけたら、テストを作成して(再現するため)、バグを修正するのがよいタイミングです。テストでバグが再現されていることが確認できれば、それが適切なテストであると確信できます。このようなバグの大部分が回帰(50%?)であることを考えると、ほとんどの場合、回帰テストを作成する価値があります。
  • コードのある領域に飛び込んで修正するときは、その領域を中心にテストを書くのがよいでしょう。コードの性質に応じて、さまざまなテストが適切です。ここで、アドバイスの1つが見つかります

OTOH、特に誰もそれを変更するつもりがない場合は、人々が満足しているコードの周りにテストを書くのをただ座っているだけの価値はありません。それは価値を追加しないだけです(システムの動作を理解することを除いて)。

幸運を!



1

私があなたの立場にいたら、システム全体を機能させる機能テストから始めて、おそらくアウトサイドインのアプローチをとるでしょう。RSpecのようなBDD仕様言語を使用してシステムの要件を再文書化し、ユーザーインターフェイスを自動化することでそれらの要件を確認するテストを記述しようと思います。

次に、新しく発見されたバグの欠陥駆動型開発を行い、ユニットテストを記述して問題を再現し、テストに合格するまでバグに取り組みます。

新機能については、アウトサイドインアプローチを使用します。RSpecに記載されている機能から始めて、ユーザーインターフェースを自動化して検証します(もちろん、最初は失敗します)。次に、実装が進むにつれて、より細かいユニットテストを追加します。

私はプロセスの専門家ではありませんが、わずかな経験から、自動UIテストによるBDDは簡単ではないことをお伝えできますが、努力する価値はあり、おそらくあなたのケースで最も大きなメリットが得られると思います。


1

私は決してベテランのTDDエキスパートではありませんが、もちろん単体テストはできる限り重要であると信じています。コードは既に用意されているので、まずはある種の単体テストの自動化を準備することから始めます。TeamCityを使用して、プロジェクトのすべてのテストを実行します。これにより、コンポーネントがどのように実行したかについての概要がわかります。

それが整ったら、失敗することのない本当に重要なビジネスロジックのようなコンポーネントに移ります。私の場合、さまざまな入力に対して解決する必要のあるいくつかの基本的な三角法の問題があるので、それらの問題をテストします。私はこれを行う理由は、私は真夜中の油を燃やしていたときに、それはあなたがいるので、本当に、感動する必要がないこと、コードの深さまで掘り時間を無駄にするのは非常に簡単だということです彼らがテストされる知っている可能な入力のすべてについて(私の場合、入力の数は有限です)。

さて、あなたはうまくいけば、それらの重要な部分についてより良く感じるでしょう。座ってすべてのテストを打ち消す代わりに、私はそれらが出てきたら攻撃します。修正すべき本当のPITAであるバグに遭遇した場合は、そのための単体テストを記述して、邪魔にならないようにします。

テストから特定のクラスをインスタンス化できないため、テストが難しい場合があるため、モックする必要があります。ああ、でもインターフェイスに書いていないので簡単にモックできないかもしれません。私はこれらの「おっと」シナリオを、上記のインターフェースを実装する機会と捉えています。なぜなら、それはまあ、それは良いことだからです。

そこから、ビルドサーバーまたはコードカバレッジツールで構成した自動化を取得します。それらは、カバレッジが悪い大きな赤いゾーンを持つ厄介な棒グラフを作成します。100%のカバレッジは目標ではなく、100%のカバレッジは必ずしもコードが完全なものであることを意味するわけではありませんが、自由時間があるとき、赤いバーが私にやる気を起こさせます。:)


1

良い答えがたくさんあるので、内容を繰り返さないようにします。私はあなたのプロフィールを確認しましたが、あなたはC#.NET開発者のようです。そのため、レガシーコードの単体テストの自動生成に役立つMicrosoft PEXおよびMolesプロジェクトへの参照を追加します。自動生成が最善の方法ではないことは知っていますが、少なくともそれを開始する方法です。レガシーコードにPEXを使用することに関するMSDNマガジンの非常に興味深い記事を確認してください。


1

TopTalエンジニアによる素晴らしい記事を読んで、テストの追加をどこから始めるべきかを説明することをお勧めします。これには多くの数学が含まれていますが、基本的な考え方は次のとおりです。

1)コードの求心性カップリング(CA)を測定します(クラスが他のクラスによってどれだけ使用されているか、つまり、それを壊すと広範囲にわたる損傷が発生します)

2)コードの循環的複雑度(CC)を測定します(複雑度が高い=遮断の変化が大きい)

CAとCCが高いクラスを特定する必要があります。つまり、関数f(CA、CC)があり、2つのメトリックの最も小さいクラスに、テストカバレッジの最高の優先順位を与える必要があります。

どうして?なぜなら、CAは高いがCCは非常に低いクラスが非常に重要ですが、破られる可能性は低いからです。一方、CAが低いがCCが高いと壊れる可能性がありますが、被害は少なくなります。だからあなたはバランスをとりたいです。


0


状況によって異なります... 単体テストを行うのは素晴らしいことですが、バグのない製品を入手するには、ユーザーが誰であり、何を許容できるかを検討する必要があります。現在のところ単体テストのないコードをリファクタリングすると必然的にバグが発生し、多くのユーザーは、長期的に見れば製品の一時的な欠陥を増やして欠陥を少なくしていることを理解するのが難しくなります。最終的には、最終的な決定権を持つのはユーザーです...


-2

はい。いいえ。テストを追加しています。

より多くのTDDアプローチに向かっていくと、実際には、新しい機能を追加し、回帰テストをはるかに容易にするための努力がよりよく伝えられます。見てみな!

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