コードカバレッジを劇的に改善する方法は?


21

ユニットテストの下でレガシーアプリケーションを取得することを任されています。アプリケーションに関する最初の背景:これらの主要な問題を伴う600k LOC Java RCPコードベースです。

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

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

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


回帰テストを自動的に作成し、それぞれを個別に検証してみませんか?それらをすべて手書きで書くよりも速くする必要があります。
ロバートハーヴェイ

Javaのレガシーで書かれたものを呼び出すのは少しおかしいように聞こえますが、確かにレガシーです。システムをリファクタリングして単体テストを作成することを恐れないことを言及しましたが、リファクタリングを試みる前に、システムに単体テストをそのまま書くべきではありませんか?次に、リファクタリングを同じユニットテストで実行して、何も壊れていないことを確認できますか?
dodgy_coder

1
@dodgy_coderは通常は同意しますが、効率的に機能する従来のQAがしばらくの間私を安心させることを願っています。
ピーターコフラー

1
@dodgy_coder Michael C. Feathers、レガシーコードの効果的な作成の著者は、レガシーコードを「テストなしのコード」と定義しています。有用な定義として役立ちます。
StuperUser

回答:


10

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

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

カテゴリ1は開始する明らかな場所であり、比較的少ない作業で多くのメリットを得ることができます。カテゴリ2を使用すると、カバレッジ統計を迅速に改善し(士気に適しています)、コードベースの使用経験を増やすことができます。一方、カテゴリ3はより多く(多くの場合イライラする)作業ですが、より多くのメリットをもたらします。あなたが最初にすべきことは、あなたにとって士気とカバレージ統計がどれほど重要かによって異なります。カテゴリ4はおそらく気にする価値はありません。


優れた。依存関係カウント/テスト可能性エクスプローラーなど、静的分析で簡単に確認できるかどうかを判断する方法があります。しかし、コードが脆弱かどうかをどのように判断できますか?欠陥を特定のユニット(クラスなど)に一致させることはできません。もちろん、それが3位であれば(神のクラス/シングルトン)。だから多分チェックイン(ホットスポット)の数?
ピーターコフラー

1
@Peter Kofler:ホットスポットのコミットは良いアイデアですが、この種の知識の最も価値のあるソースは、コードを操作した開発者です。
マイケルボルグ

1
@Peter-Michaelが言ったように、コードを操作した開発者。大規模なコードベースをかなりの時間使用したことがある人なら、そのコードのどの部分の匂いがするかを知っているでしょう。または、全体が臭いがする場合、そのどの部分が本当に臭いです。
カーソン63000年

15

これよりはるかに大きいレガシーシステム(Javaではない)での作業経験が豊富です。悪い知らせを伝えるのは嫌いです。あなたの問題はあなたの問題の大きさです。あなたはそれを過小評価していると思います。

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

あなたがすぐに報道を得ようとするなら、あなたは仕事を急いで、それを半分焼いて、失敗するでしょう。このテストでは、明らかな部分を部分的にカバーし、実際の問題をカバーすることはできません。あなたは、ユニットテストにそれを売り込もうとしているまさにそのマネージャーは、それが価値がないこと、それが機能しない単なる別の特効薬であると確信するでしょう。

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

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


+1、コードよりも強力な標準がなければ、何かを効果的に単体テストすることはできません。
dan_waterworth

私は知っていますし、同意します。違いは、QAを適切に機能させることによる従来の回帰テストがあるため、何らかのセーフティネットが存在することです。第二に、私はユニットテストに深く賛成しているので、それは間違いなく機能しなかった別のものではありません。最初に何をターゲットにするかについての良い点。ありがとう。
ピーターコフラー

1
また、「カバレッジ」を目指すだけでは品質の向上につながらないので、欠陥のある些細なテスト(および明示的なテストを必要としない些細なコードのテスト)に悩まされることを忘れないでください。カバレッジを増やすためだけに追加されます)。テストを作成することなく、カバレッジツールを満足させるためにテストを作成することになります。テストを書くことなく、テストカバレッジを高めるためにコード自体を変更する可能性があります(コメントや変数の定義を切り取るなど、カバーされていないコードを呼び出します)。
11

2

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

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

現実的には、コードを作成してしまえば、重要なものを見落とすリスクを冒さずにテストを効果的に作成するのはほとんど遅すぎます。一方、一部のテストはテストなしよりも優れていると言えますが、その場合は、テスト自体がシステム全体に価値を追加することを示す必要があります。

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

覚えておくべきことは、経営陣はコスト/便益に関心があり、それが顧客や最終的には予算に直接影響することです。彼らは、彼らが興味を持っている利益を彼らが提供することを証明できない限り、それが最善であるという理由だけで何かをすることに決して興味を持ちません。システムを改善し、現在行っている作業のテストカバレッジが良好であることを示すことができれば、管理者はこれをあなたの努力の効率的なアプリケーションと見なす可能性が高くなります。これにより、製品の開発を完全に凍結することなく、さらに悪いことに書き換えを主張することがほぼ不可能であることを要求することなく、他の主要分野に努力を拡大することを主張することができます!


1

カバレッジを改善する1つの方法は、さらにテストを書くことです。

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

a、b、およびb 'の3つのコードブロックがあり、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に適切な名前を付けるようにしてください。そうすれば、より良いテストカバレッジと、よりメンテナンスしやすいプログラムが得られます。

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