複雑度と単体テストケース数の相関関係
garyoさんから、ソースの複雑度と単体テストケース数について有益なアドバイスを示唆してもらったので、メモしておく。
SourceMonitorはフリーで、以下の言語のソースのソフトウェア複雑度(McCabeのサイクロマチック数)を測定できる。
例:C++, C, C#, VB.NET, Java, Delphi, Visual Basic (VB6) or HTML
◆McCabe's cyclomatic complexity
SourceMonitorで求められる複雑度(McCabeのサイクロマチック数)は、モジュール内の分岐の数(+ループの数)で計算される。
複雑度の数値は、下記の意味を持つらしい。
10 以下であればよい構造
30 を越える場合,構造に疑問
50 を越える場合,テストが不可能
75 を越える場合,いかなる変更も誤修正を生む原因を作る
話によると、複雑度が15以上ならばコードレビューを実施する会社もあるらしい。
当然、複雑度が大きいソースはIF文やFor文がネストしまくっている場合が多いから、複雑度が小さくなるようにリファクタリングする。
ソースをリファクタリングすべきかどうか判断する場合に、複雑度のメトリクスは使えるだろう。
更に、複雑度と分岐網羅(C1)は、下記によれば、ほぼ等しい関係にある。
M(循環的複雑度 ) は、完全な分岐網羅率(C1)を達成するのに必要なテストケース数の上限である。
一般に、あるモジュールを完全にテストしようとした場合、全ての実行経路を通す必要がある。これの意味するところは、循環的複雑度の大きいモジュールの方が経路数が多く、従ってテストケースも多く必要になるということである。また、複雑度の大きいモジュールは、ソースコードの意味を理解するのに多くの経路を追わなければならず、読解がより困難になる。
また、複雑度の大きいモジュールは凝集度が低いと予想される。この相関を想定する理由は、分岐点(判断ポイント)が多いモジュールは、単一の機能以上のものを詰め込もうとしている可能性が高いためである。
つまり、下記の結論が得られる。
ソフトウェア複雑度(McCabeのサイクロマチック数)
≒分岐網羅(C1)のテストケース数
≒単体テストケース数
JUnitを使っているならば、djUnitで単体テストのカバレッジが100%になるようにテストプログラムを作る。
この時、djUnitでカバレッジ100%になるためのテストメソッド数は、分岐網羅のテストケース数以上になるはずだろう。
つまり、ソフトウェア複雑度で得られる数値よりもテストメソッド数が少ないならば、最低限の単体テストをクリアしていないことになる。
実際の単体テストでは、分岐網羅のテストは当たり前であって、条件網羅(C2)のテストを完全でなくとも近いレベルまでテストしなければ、ケース漏れしているだろう。
SourceMonitorを実際に使ってみたら、複雑度が50(!)のソースもあった。
これは、分岐網羅のテストケース数だけで50個必要なわけで、単体テストでケース漏れが発生している可能性は高い。
昨今の業務システムは、フレームワークによる自動生成やテストプログラムも含めれば、10万行近いソース行数は当たり前。
例えば、プログラム1個当たり100行で、1000個のプログラムから業務システムが成り立っているとする。
そのシステム内のプログラムの複雑度の平均が10だとすると、単純に計算すれば、1万個の単体テストケース数が必要になる。
実際はテスト不要のプログラムもあるから、ケース数は減るだろうが、これだけの規模の単体テストをこなさなければ、品質を確保できないのが実情だろう。
いくらテスト駆動開発を実践していると言っても、単体テスト品質をクリアするために必要な最低限のケース数は必要。
ソフトウェアテストの知識無しでJUnitを使えば、無意味にケース数が増えてしまい、コストの割が合わなくなる。
JUnitを使っているなら、djUnitでテストのカバレッジを測定できる。
その時、最低限のテストケース数でもって100%網羅するように作る時に、上記の法則が役立つだろう。
テスト駆動開発に従事するプログラマは、テストケースの品質Upに注力しないといけない。
【参考ページ】
◆ソースコードのメトリクス(品質測定)を行うツール - ふにゃるん
コードの複雑度の判定基準は、"Complexity"のようです。このパラメータが"McCabeのサイクロマチック数"で合っているのかな?と思って、色々チェックしてみたんですが、「合って」いる模様です。
命令網羅(C0)、分岐網羅(C1)、条件網羅(C2)の説明がある。
【追記】
@akiyama924さんの指摘の通り、分岐網羅(C1)の場合、テストケース数は、ソフトウェア複雑度で得られる数値よりも小さくなる場合はある。
しかし、だからと言って、「 if (conditionXX) {xxx;} という行が10個並んでいるだけのコード」は、たった2個のテストケースだけで十分とは言えない。
まともなレビューアならば、条件網羅に近いテストでやり直せ、と突き返すだろう。
言いたかったのは、ソフトウェア複雑度に比例してテストケース数も増えるよ、ということかな。
akiyama924さんのツイート: "書きたかったのは、「ソースコードがどんな構造であったとしてもMcCabeの複雑度の数以内のテストケースで分岐カバレッジを100%とするテストを実施可能」かな。"
| 固定リンク
「ソフトウェア工学」カテゴリの記事
- 「システムアーキテクチャ構築の原理」の感想part2~非機能要件がシステムのアーキテクチャに影響を与える観点をプロセス化する(2024.05.06)
- 「システムアーキテクチャ構築の原理」の感想(2024.05.06)
- ソフトウェア工学の根本問題から最近のソフトウェア設計を考えてみる(2024.03.03)
- マイクロサービス設計は従来のアーキテクチャ設計と何が違うのか(2024.01.02)
- 「ソフトウェアアーキテクチャ・ハードパーツ」の情報リンク~マイクロサービスの設計技法の課題は何なのか(2023.11.12)
コメント