web-dev-qa-db-ja.com

コードカバレッジを大幅に改善するには?

私はユニットテストでレガシーアプリケーションを取得する任務があります。アプリケーションに関する最初の背景:これは600kのLOCですJava RCPコードベースで、これらの主要な問題があります

  • 大規模なコードの重複
  • カプセル化は行われません。ほとんどのプライベートデータには外部からアクセスできます。ビジネスデータの一部はシングルトンになっているため、外部からだけでなく、どこからでも変更できます。
  • 抽象化(ビジネスモデル、ビジネスデータがObject []とdouble [] []に格納されるなど)がないため、オブジェクト指向はありません。

優れた回帰テストスイートがあり、効率的なQAチームがバグのテストと発見を行っています。私は古典的な本からそれをテストする方法を知っています。マイケルフェザーズ、しかしそれは遅すぎる。動作する回帰テストシステムがあるので、ユニットテストを作成できるようにシステムを積極的にリファクタリングすることを恐れません。

カバレッジをすばやく取得するために、どのように問題への攻撃を開始する必要がありますかですから、管理に進捗を示すことができます(実際、JUnitテストのセーフティネットから収益を得ることができます)?ツールを使用して、回帰テストスイートを生成したくありません。 AgitarOne、これらのテストは何かが正しいかどうかをテストしないためです。

21
Peter Kofler

単体テストを導入する場合、コードを配置できる主な軸は2つあると思います。A)コードはどの程度テスト可能ですか?およびB)それはどれくらい安定していますか(つまり、どれほど緊急にテストが必要ですか)?極端なものだけを見ると、これにより4つのカテゴリが生成されます。

  1. テストが容易で脆弱なコード
  2. テストが簡単で安定したコード
  3. テストが難しく、もろいコード
  4. テストが難しく、安定しているコード

カテゴリ1は、比較的少ない作業で多くの利益を得ることができる最初の明白な場所です。カテゴリ2はカバレッジ統計(士気に良い)をすばやく改善し、コードベースの経験を積むことができますが、カテゴリ3はより多くの(しばしばイライラする)作業ですが、より多くの利益をもたらします。最初にすべきことは、士気と報道の統計があなたにとってどれほど重要かによって異なります。カテゴリ4はおそらく気にする価値はありません。

10

私はレガシーシステムでの作業に多くの経験があります(Javaではありません)、これよりはるかに大きくなります)。あなたはそれを過小評価していると思われます。

レガシーコードに回帰テストを追加することは、遅くて費用のかかるプロセスです。多くの要件は十分に文書化されていません-ここでのバグ修正、そこでのパッチ、そしてあなたがそれを知る前に、ソフトウェアはそれ自身の振る舞いを定義します。テストがないということは、実装がすべて揃っていることを意味し、コードに実装された暗黙の要件に「挑戦」するためのテストはありません。

カバレッジをすばやく取得しようとすると、ジョブを急いで半分焼き、失敗する可能性があります。テストは明らかなものを部分的にカバーし、実際の問題をカバーすることはできません。あなたはユニットテストにそれを売ろうとしているまさにそのマネージャーに価値がない、それは機能しないもう一つの特効薬であることを納得させるでしょう。

私見、最善のアプローチはあなたのテストをターゲットにすることです。メトリック、直感、および欠陥ログレポートを使用して、最大の問題を引き起こすコードの1%または10%を特定します。これらのモジュールを強く攻撃し、残りは無視してください。やりすぎないようにしてください。

現実的な目標は、「UTを実装してから、テスト中のモジュールへの欠陥の挿入がUT以外のモジュールのx%に減少した」ことです(理想的にはxは100未満の数値です)。

15
mattnz

カバレッジを改善する1つの方法は、より多くのテストを作成することです。

もう1つの方法は、既存のテストが現在カバーされていない冗長コードを実際にカバーするように、コードの冗長性を減らすことです。

3つのコードブロック、a、b、およびb 'があるとします。ここで、b'はBの複製(完全コピーまたはニアミスコピー)であり、テストTでaおよびbをカバーしているが、b 'はカバーしていないとします。

Bとb 'からBとして共通性を抽出することによってb'を排除するためにコードベースをリファクタリングする場合、コードベースはa、b0、B、b'0のようになり、b0にはb'0の非共有コードが含まれ、逆も同様です。逆に、b0とb'0の両方がBよりもはるかに小さく、Bの呼び出し/使用。

プログラムの機能は変更されておらず、テストTも変更されていないため、Tを再度実行して合格することが期待できます。現在カバーされているコードは、a、b0、およびBですが、b'0ではありません。コードベースは小さくなり(b'0はb 'よりも小さい!)、元々カバーしていたものをカバーします。カバー率が上がりました。

これを行うには、リファクタリングを有効にするために、b、b '、理想的にはBを見つける必要があります。私たちの CloneDR ツールは、特にJavaを含む多くの言語でこれを行うことができます。あなたのコードベースには多くの重複したコードがあると言っています。これはあなたの利益のためにそれに取り組む良い方法かもしれません。

奇妙なことに、bとb 'を見つけるという行為は、プログラムが実装する抽象的なアイデアについての語彙を増やすことがよくあります。ツールはbとb 'が何をしているのかわからないが、コードからそれらを分離するまさにその行為は、bとb'のコンテンツに単純に焦点を当てることを可能にし、多くの場合、プログラマーに、クローン化されたコードが実装する抽象化B_abstractの非常に良いアイデアを与える。これにより、コードの理解も向上します。 Bを抽象化するときは、Bに適切な名前を付けてください。そうすれば、テストカバレッジが向上し、プログラムが保守しやすくなります。

2
Ira Baxter

馬が既にボルトで締められているとき、納屋のドアについて心配しないと言っていることを思い出します。

実際には、レガシーシステムの適切なテストカバレッジを取得するための費用対効果の高い方法は確かになく、短期間ではありません。 MattNzが述べたように、それは非常に時間がかかるプロセスであり、最終的には極端にコストがかかります。私の直感は、管理に印象を与えるために何かを行おうとすると、テストしようとしている要件を完全に理解せずに、あまりにも早く表示しようとするため、新しいメンテナンスの悪夢を作る可能性があると私に言います。

現実的には、すでにコードを記述してしまえば、重要なものを見落とすリスクを冒さずにテストを効果的に書くのはほとんど遅くなります。一方、一部のテストはテストなしよりも優れていると言えるかもしれませんが、そうであれば、テスト自体がシステム全体に付加価値を与えることを示す必要があります。

私の提案は、何かが「壊れている」と感じる重要な領域を調べることです。つまり、それはコードがひどく非効率的である可能性があること、または以前に維持するのにコストがかかっていたことを実証できることを意味します。問題を文書化し、これを開始点として使用して、大規模なリエンジニアリング作業に着手することなく、システムの改善に役立つレベルのテストを導入します。ここでの考え方は、テストに追いつくことを避け、特定の問題を解決するのに役立つテストを導入することです。しばらくして、コードのそのセクションを維持するための以前のコストと、サポートテストで適用した修正による現在の取り組みを測定して区別できるかどうかを確認します。

覚えておかなければならないのは、経営陣はコスト/利益と、それが顧客、そして最終的には彼らの予算にどのように直接影響するかについてより関心があるということです。それが彼らに彼らに興味のある利益を彼らに提供するであろうことを証明することができない限り、それがすることが最善のことであるから、彼らは単に何かをすることに決して興味がない。システムを改善し、現在行っている作業のテストカバレッジが適切であることを示すことができれば、経営陣はこれを自分の取り組みの効率的なアプリケーションと見なす可能性が高くなります。これにより、製品の開発を完全に凍結したり、最悪の場合、書き直しを主張することがほぼ不可能になったりすることなく、他の重要な領域に努力を拡大することを主張できる可能性があります。

2
S.Robins