≒対象関数に分岐がどれだけあるかの度合い
≒C1(分岐網羅)の経路数
if文やfor文のような分岐のないソースコードの場合、複雑度は1。
コードに1つのif文が含まれていれば、コードには2つの分岐がある事になる。
一方はif文での条件が真となる場合の経路で、
もう一方はそれが偽となる場合の経路。複雑度は2。
では、以下のメソッドの複雑度は?
void TestFunc(bool condition1, bool condition2) { if ((condition1 == true) && (condition2 == true)) { std::cout << "Hoge" << std::endl; } }
SourceMonitorの結果を見ると、複雑度は「3」。
??という事はC1(分岐網羅)ではなく、C2(条件網羅)?
/* ------------------ Source Monitor のHelpより抜粋 -------------------- */
The complexity metric is counted
approximately as defined by Steve McConnell in his book Code Complete, Microsoft
Press, 1993, p.395. The complexity metric measures the number of execution paths
through a function or method. Each function or method has a complexity of one
plus one for each branch statement such as if, else, for, foreach, or while. Arithmetic if statements (MyBoolean ?
ValueIfTrue : ValueIfFalse) each add one count to the complexity total. A
complexity count is added for each '&&' and '||' in the logic within
if, for, while or similar logic statements.
Switch statements add complexity counts for each exit from a case (due to a break, goto, return, throw, continue, or similar statement), and one count is added for a default case even if one is not present. (Note: when a project's Modified Complexity option is selected, switch statements add a count of one to the complexity and the internal case statements do not contribute to the complexity metric.) Each catch or except statement in a try block (but not the try or finally statements) each add one count to the complexity as well.
Switch statements add complexity counts for each exit from a case (due to a break, goto, return, throw, continue, or similar statement), and one count is added for a default case even if one is not present. (Note: when a project's Modified Complexity option is selected, switch statements add a count of one to the complexity and the internal case statements do not contribute to the complexity metric.) Each catch or except statement in a try block (but not the try or finally statements) each add one count to the complexity as well.
/* ------------------------------------------------------------------ */
つまり、if文内の'&&'や'||'もカウントしているため、単に≒C1という訳ではない。
ユニットテストのTC数が十分か否かを確認するために、上記指標を用いる場合は、求められているカバレッジ(C0,C1,C2)とツールが叩き出す値の意味を考慮した上で利用する必要がある。
ちなみに循環的複雑度はグラフ理論における"Cyclomatic number"を応用したもの。
制御フローをグラフで表現した場合、
複雑度 = エッジ(枝)の数 - ノード(節点)の数 + 2
⇒グラフによって区切られた空間の数(分割領域数)に等しくなる。
ノード : 文、式、または制御合流点
(ステートメントの数)
(ステートメントの数)
エッジ : ノード間の遷移を表す有向辺
(分岐が一つもなければ「ノードの数-1」となる)
以下の関数だと、ノードの数は7で、これらを結ぶエッジの数は8(※)。
よって、複雑度は8-7+2=3となる。
void TestFunc(bool condition1, bool condition2) { int a = 1; //. ノード1 if (condition1 == true) //. ノード2 { int a = 1; //. ノード3 } int a = 1; //. ノード4 while (condition2 == true) //. ノード5 { int a=1; //. ノード6 } int a = 1; //. ノード7 }
(※)"⇒"の数がエッジ数
(condition1==true && condition2==true) ・・・ まずは全てのノードを通るパス
ノード1⇒ノード2⇒ノード3⇒ノード4⇒ノード5⇒ノード6⇒ノード7
(condition1==false)
ノード2⇒ノード4
(condition2==false)
ノード5⇒ノード7
[参考資料]
・An objection to Japanese translation of "Cyclomatic complexity"
http://a-lifelong-tester.cocolog-nifty.com/publications/STM06_An_objection_to_Japanese_translation_of_Cyclomatic_complexity.pdf
http://a-lifelong-tester.cocolog-nifty.com/publications/STM06_An_objection_to_Japanese_translation_of_Cyclomatic_complexity.pdf
・ソフトウェア工学III - プロダクトデータの解析II
0 件のコメント:
コメントを投稿