web-dev-qa-db-ja.com

予期しないコードカバレッジの削減

最初はまったくテストされていなかった既存のコードに単体テストを追加しています。

以前のビルドと比較してコードカバレッジパーセンテージが低下しているビルドを失敗するようにCIシステムをセットアップしました。主に継続的な改善の道筋を設定するためです。

次に、予期せぬ面倒な(数学的には正しいが)状況に遭遇しました。これは、次のように減らすことができます。

  • リファクタリング前:
    方法1:100行のコード、10行が対象-> 10%が対象
    方法2:20行のコード、15行が対象-> 75%が対象

    合計:25/120->〜20%のカバレッジ

  • リファクタリング後:
    方法1:100行のコード、10行がカバー-> 10%がカバレッジ(そのまま)
    方法2:5行のコード、5行が対象-> 100%が対象

    合計:15/105->〜14%のカバー率

したがって、IMOの状況は改善されましたが、私のCIシステムは明らかに同意しません。

確かに、これは非常に難解な問題であり、コードの大部分が適切にカバーされるようになるとおそらく消えますが、「改善」パスを継続して実行できるようにする可能性がある洞察とアイデア(またはツール/構成)をいただければ幸いです。私のCIシステムでカバーしています。

環境は、Java、Jenkins、JaCoCoです。

35
Jonathan Gross

これは、新しいベースラインを設定するリファクタリングのかなり明確な兆候であるため、カバーされていない行の総数も減少した場合、または行の総数が減少した場合に、相対コードカバレッジを減少させることで、ある程度影響を軽減できます。カバレッジ指標用。

あなたの例では、カバーされていないラインの総数は95ラインから90ラインに減少し、ラインの総数は120から105に減少します。これにより、相対的なカバレッジがこの状況で非常に重要ではないことを十分に確信できます。ただし、新しいコードを追加する場合、メトリックには、新しいコードの相対的なカバレッジを以前の相対的なカバレッジよりも少なくしないという期待が反映されます。

補足:これらのメトリックは、テストがコードベースの最も賢明な部分をカバーしているかどうかを示すものではないことに注意してください。

18
Doc Brown

ここで私が目にする問題は、コードカバレッジビルド失敗のトリガーを作成したことです。コードカバレッジは定期的に見直すべきものだと思いますが、経験したように、より高いコードカバレッジの追求で一時的に減少する可能性があります。

一般に、ビルドの失敗は予測可能である必要があります。以下は、適切なビルド失敗イベントを作成します。

  • コードはコンパイルされません
  • テストは実行されません
  • テストが失敗する
  • ビルド後のパッケージ化が失敗する(つまり、コンテナーを作成できないなど)
  • パッケージはリポジトリに公開できません

これらはすべて合格/不合格です量的メジャーであり、機能する(バイナリ値1)か機能しない(バイナリ値0)。

コード品質を監視する必要があります質的であるため。注:パーセンテージは、数値が関連付けられていても、定性的な尺度です。以下は定性的な測定です。

  • 循環的複雑度(定性的な概念に関連付けられた数値。つまり、その数値には定性的な意味がある)
  • 保守性インデックス(定性的な概念に関連付けられた数値。つまり、その数値には定性的な意味がある)
  • カバーされるライン/ブランチ/メソッドのパーセンテージ(定量的結果の定性的要約)
  • 静的解析結果(含まれる数値なし)

他の傾向と同様に、過去のリリースを調べると、全体的な傾向が改善または変化しない間、一時的な減少が見られます(100%は100%のままです)。長期的な傾向がテストされていない、または保守可能なコードに向かっている場合、対処する必要があるチームの問題があります。長期的な傾向が測定に基づく高品質のコードである場合、チームは仕事をしています。

47
Berin Loritsch

コードカバレッジメトリックを使用しないことを検討しましたか?

コードカバレッジがあなたが見るべきものではないことを主張するつもりはありません。絶対です。ビルド前とビルド後にカバーされた内容を追跡することは良いことです。また、変更のコード行の新しい行と変更された行をカバーしていることを確認するのも良い方法です(環境によっては、これを容易にするツールになる場合があります)。

しかし、今見ているように、カバーされた行のパーセンテージが下がるように、カバーされた行をリファクタリングして削除することができます。私はあなたの推論に同意します-論理的な範囲は変わっていません。また、コードの他の側面も簡略化していると思います(たとえば、リファクタリングの前後でさまざまな複雑さの測定値がどのように変化したかについて知りたいと思います)。しかし、計算は正しいです。カバーされた行のパーセンテージは、実際には下がりました。

さらに、コードカバレッジは、テストの有効性や品質についてはまったく何も述べていません。また、コードの一部の背後にあるリスクについては何も述べていません。システムの品質にそれほど信頼性を与えずに、些細なラインをカバーするテストや最も単純なロジックをチェックするテストを書くのは比較的簡単です。

37
Thomas Owens

これはシンプソンのパラドックスと呼ばれ、このアプローチでよく知られている統計上の問題です。
リファクタリングした後でケースを構築することもできますすべての単一メソッドのカバレッジは高くなりますが、全体のカバレッジはまだ下がりました

全体的なパーセンテージではなく、キャッチしたいタイプの「回帰」をキャッチする他の方法を見つける必要があります(私はそれを読んだときのアプローチが好きでしたが)。

14
Aganju

すべての回答は、品質指標としてコードカバレッジを使用しないように指示していますが、実際に質問に回答したものはありません。カバレッジを減らしてどうするか?
答えは非常に簡単です。パーセントではなく絶対数を使用してください。カバレッジ率よりも重要なのは、テストされていない関数の数とテストされていないブランチの数です。また、テストされていない関数とブランチのリストを取得すると便利です。

5
BЈовић

これに役立つ1つのオプションは、回線カバレッジからブランチカバレッジに切り替えることです。関数のブランチを減らすと、カバーされていないブランチで同様の状況に遭遇する可能性があるので、「助けになる」と言います。

ただし、全体として、ブランチカバレッジはラインカバレッジよりも意味のあるメトリックです。そして、長いメソッドを短いメソッドにリファクタリングすると、通常は分岐するよりもコードの行数が減ると思います。もちろん、それが本当に厄介なコードであれば、多くのブランチを枝刈りすることになるかもしれません。その場合でも、枝を数える方がいいと思います。

2
JimmyJames

あなたがしていることは間違っていません。コードカバレッジは驚くべきメトリックではありませんが、便利なメトリックです。それはあなたのコードが完全にテストされていることを告げるものではありません。しかし、テストに期待する標準のレベルがないことも悪い考えです。

この問題を解決する1つの方法は、変更が正当化されると思われる場合は、単に制限を変更することです。この種のハード制限の要点は、何か悪いことが起こったときにすぐに通知することです。多くの場合、この削減は意図的ではなく、より多くのより良いテストを導入することで修正する必要があります。ただし、エラーが誤検出であると特定し、削減が期待されていることを自分自身とチームに証明できる場合は、制限を削減しても問題ありません。

別の方法は、その減少を「ソフト」障害に変えることです。たとえば、ジェンキンスはビルドの結果が「不安定」になる可能性があります。不安定なビルドでは、最終的なアーティファクトは引き続き使用できますが、機能がいくらか低下する可能性があります。これにより、テストを拡張する必要がある場合や制限を下げる必要がある場合に、何をすべきかを決定する時間が与えられます。これは、2つの異なるビルドを使用して実装することもできます。1つはチェックと制限が少ないビルドアーティファクトで、失敗するとアーティファクトすら使用できなくなります。次に、品質メトリックのいずれかが壊れた場合に失敗する非常に厳しい制限があります。

2
Euphoric

Berin Loritschからの回答に加えて、突然変異テストと呼ばれる手法にも注目したいと思います(Javaツールについては https://pitest.org/ を参照) 。

変異テストは、コードの行を変更して動作が異なり、ユニットテストが失敗しないようにするメトリックを提供します。

あなたのケースでは、リファクタリングがうまく行われていれば、変異テストのメトリックが改善されているはずです(ユニットテストのラインカバレッジのパーセンテージとして表すと)。

このリンクは、いくつかの(Java関連)ミューテーションテストツールについて説明しています: https://pitest.org/Java_mutation_testing_systems/

1

リファクタリング前:95のテストされていない行。

リファクタリング後:90のテストされていない行。

テストしていない行の数を常に考慮する必要があります。

コードカバレッジパーセンテージは、コードが常に大きくなる場合にのみ、これを適切に測定できます。これは残念です。

別の言い方をすると、テストを中断することなく、コードの行数を減らすことができれば、コードカバレッジの割合を無視するすべての権利があります。

1
Pedro A

問題は次のとおりです。コードカバレッジが非常に少ない1つの巨大な関数があるため、パーセンテージを上げるには、カバーされたコード行を追加する必要があります。 20行/ 10カバーを追加すると、5行/ 5カバーを超えるパーセンテージが向上します。速度が重要で、最初の関数が「if(簡単なケース){簡単なケースをすばやく処理する} else {複雑なケースをゆっくりと処理する}」であり、2番目が「すべてのケースをゆっくりと処理する」だったとしても、 。

つまり、測定を改善してもコードの品質が改善されないという測定可能なものがあるということです。つまり、常識が同時に適用されている場合にのみ、これをターゲットとして使用する必要があります。 「モチベーション」についての本から:最も重要なことは、モチベーションに従ってより良い結果を生み出すような方法で人々をモチベーションにすることです。

「int x = 100;」という行がある関数があるとします。コードカバレッジを改善するために、「int x = 0; x ++; x ++;(100回繰り返す)」に変更します。 1つのカバーされたラインの代わりに、101のカバーされたラインがあります。総コードカバレッジが上がり、ボーナスがもらえます。

0
gnasher729

これは、コードカバレッジメトリックの定義の変更や、ポリシーへの免除の要求/付与を含まないソリューションです。ただし、前述のポリシーには間違いがあるため、カバーされていない行の総数をカウントするか、単調性を要求する代わりにファイルごとの下限(80%など)を適用する方がよい場合があります。

方法2のリファクタリングの前または同時に、方法1のコードカバレッジを改善します。

質問に述べられている現在の状況は次のとおりです。

                    Old World                   New World

           covered  total   %           covered  total   %
 Method 1       10    100  10                10    100  10
 Method 2       15     20  75                 5      5 100
Aggregate       25    120  20.8              15    105  14.3

新世界では、メトリックが減少しないためには、カバーされる行の総数は少なくとも22である必要があります。 (105 * 25 / 120の上限は22です)。

したがって、Method 1Method 2が存在するファイルの7行をカバーするテストを追加するだけで済みます。

このソリューションには、コードカバレッジの単調性ルールを満たすために、同じコミットに無関係な変更が含まれるという欠点があります。方法2へのこの1つの変更が、ポリシーの変更を正当化するほど重要ではない場合でも、実行する価値があります。ポリシーを変更する前にこの変更を最初に取得したい場合も、行う価値があります。

0
Gregory Nisbet