私にはこのスイッチシステムがあり、eclemmaを使用してブランチカバレッジをテストしています。すべてに対してブランチカバレッジで少なくとも80%が必要なので、できる限りテストするようにしています。ただし、このスイッチシステムはブランチカバレッジに関して十分にテストされていないことがeclemmaからわかりました。
pos = p.getCurrentPosition().substring(0, 1);
switch (pos) {
case "G":
goalkeepers++;
break;
case "D":
defense++;
break;
case "M":
midfield++;
break;
case "F":
offense++;
break;
case "S":
substitutes++;
break;
case "R":
reserves++;
break;
}
私はこれらの各ケースを通過するために簡単なJUnitテストを使用しました。それでもエクレマはこれを黄色としてマークし、「19のブランチのうち7つが失敗した」と言います。このスイッチシステムを通過する方法は7つしかありません(6つの個別のケース+すべて未定義)。
スタックオーバーフローで同様の質問を検索してみました。それらのいくつかは、完全なカバレッジのためにif/elseを使用するソリューションとしてありました。これがこのカバレッジを取得する唯一の方法であるかどうかはわかりません。
これらの19のブランチすべてがどこから来ているのか、このスイッチのケースで100%のブランチカバレッジを取得するためにこれらの7つのブランチをテストする方法を誰かが説明できますか?
Javaコンパイラは、switch-caseコードをtableswitch
またはlookupswitch
に変換します。tableswitch
は、異なるケースの間にはいくつかのギャップがあります。それ以外の場合、lookupswitch
が使用されます。
あなたのケースではtableswitch
が使用されますあなたのケースのハッシュコードは間隔が狭いためです(owaismによって参照されるコードとは異なります):
16: tableswitch { // 68 to 83
68: 111 // 'D'
69: 183
70: 141 // 'F'
71: 96 // 'G'
72: 183
73: 183
74: 183
75: 183
76: 183
77: 126 // 'M'
78: 183
79: 183
80: 183
81: 183
82: 171 // 'R'
83: 156 // 'S'
default: 183
}
コロンの左側の番号は、順序付けされたハッシュコードとそれらの間の埋められたギャップです。右側の番号は、ジャンプ先です。 (Javaでは、文字のハッシュコードはASCII値です。)
68
は "D"(最低のもの)のハッシュコードであり、83
は "S"(最高のもの)のハッシュコードです。 69
は、実際のケース間のギャップの1つの値であり、デフォルトのケースにジャンプします。
ただし、EclEmmaはこれらの分岐をtableswitch
のカバレッジ計算から除外すると想定しています(ギャップがあるため、カバレッジがさらに低下します)。 0(カウントされた)ブランチはまだあります
次に、文字列値の等価比較が各ジャンプ先で実行されます(デフォルトの場合を除く)。 switch-caseは6つのケースで構成されているため、等しい比較で6つの6つのジャンプ先があります。
ケース「G」の比較のバイトコードは次のとおりです。
96: aload_3
97: ldc #10
99: invokevirtual #11 Java/lang/Object;)Z
102: ifeq 183
105: iconst_0
106: istore 4
108: goto 183
111: aload_3
EclEmmaは2つの分岐をカウントします。入力文字列とケース文字列が等しいか、等しくないかのいずれかです。したがって、比較のために6 * 2分岐があります(デフォルトのケースでは分岐しません)。
次に、2つの文字列が等しい場合、ケースのインデックスが格納されます(バイトコード行105-106
( "G"の場合)。次に、2番目のtableswitch
へのジャンプが実行されます。それ以外の場合、ジャンプは直接実行されます。
185: tableswitch { // 0 to 5
0: 224
1: 237
2: 250
3: 263
4: 276
5: 289
default: 299
}
このスイッチは、以前に格納されたケースインデックスで動作し、ケース内のコードにジャンプします(ケース "G"にはインデックス0
、デフォルトのケースには-1
)。 EclEmmaカウント7ブランチ(6ケースとデフォルトケース)
したがって、最初のtableswitch
にはカウントされたブランチが0個あり、equals
の比較には12個のブランチがあり、2番目のtableswitch
にはさらに7個のブランチがあります。全体として、これは19のブランチになります
あなたのテストは6つの等しくないブランチをカバーしていません。これらをカバーするには、各ケースの文字列を見つける必要があります。ケース条件と等しくないが、同じハッシュコードを持っている。それは可能ですが、明らかに賢明ではありません...
おそらく、EclEmmaの分岐カウントは将来調整されるでしょう。
さらに、どのケースにも一致しないテストケースがないと思います(したがって、(暗黙)デフォルトのケースは対象外です)
次のリンクを確認してください: http://sourceforge.net/p/eclemma/discussion/614869/thread/80e770df/
以下は、上記のリンクからの抜粋です。
これは、3つのケースを持つスイッチの例です。
これは非常に興味深い観察です。バイトコードを見ると、Javaコンパイラが文字列の切り替えをどのように処理するかがわかります。実際には3つのステップのプロセスです。
- ハッシュコードをオンにします(3つのブランチ、1つのデフォルト)
- 各ハッシュコードに対して等号(3 * 2ブランチ)を実行します
- ケースを実際に実行するための最後の切り替えを行います(3つのブランチ、1つのデフォルト)
したがって、合計14のブランチがあり、ソースコードの観点からは奇妙に見えます。さらに奇妙に見えるのは、3つ欠けていることです。説明は、ハッシュコードの後に、equalsメソッドが追加で適用されるステップ2です。これらのブランチをカバーするには、同じハッシュコードを持つ他の文字列を見つける必要があります。これは間違いなく、JaCoCoの将来のバージョンでカバレッジレポートから除外される可能性があるものです。
https://sourceforge.net/apps/trac/eclemma/wiki/FilteringOptions