28

私はこのスイッチ システムを持っており、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 テストを使用して、これらの各ケースを調べました。それでも eclemma はこれを黄色でマークし、「19 のブランチのうち 7 つが失敗しました」と表示します。この切り替えシステムを通過する方法は 7 つしかないと思います (6 つの個別のケース + すべて未定義)。

スタックオーバーフローに関する同様の質問を検索してみました。それらのいくつかは、完全なカバレッジのために if/else を使用するソリューションとしてありました。これがこのカバレッジを取得する唯一の方法であるかどうかはわかりません。

これら 19 のブランチすべてがどこから来たのか、また、残りの 7 つをテストして、このスイッチ ケースで 100% のブランチ カバレッジを得る方法を誰か説明できますか?

4

2 に答える 2

36

Java コンパイラは、switch-case コードをtableswitchまたは に変換しlookupswitchます。はtableswitch、異なるケース間にわずかなギャップがある場合に使用されます。それ以外の場合は、lookupswitchが使用されます。

tableswitchあなたのケースでは、あなたのケースのハッシュコードの間隔が狭いため、aが使用されます(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 はこれらの分岐を a のカバレッジ計算から除外すると想定していますtableswitch(ギャップのためにカバレッジがさらに低下します)。したがって、まだ 0 (カウント) のブランチがあります。

次に、各ジャンプ先 (デフォルトの場合を除く) で文字列値の等号比較が実行されます。switch-case は 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」のバイト コード行)。次に、秒へのジャンプtableswitchが実行されます。それ以外の場合、ジャンプは直接実行されます。

 185: tableswitch   { // 0 to 5
                 0: 224
                 1: 237
                 2: 250
                 3: 263
                 4: 276
                 5: 289
           default: 299
      }

このスイッチは、以前に格納されたケース インデックスで動作し、ケース内のコードにジャンプします (ケース "G" には index0があり、デフォルト ケースには があります-1)。EclEmma は7 つのブランチをカウントします (6 つのケースとデフォルトのケース)。

したがって、最初の ではカウントされたブランチが 0tableswitchで、比較では 12 のブランチがありequals、2 番目の ではさらに 7 つのブランチがありtableswitchます。全体として、これにより 19 の分岐が生じます。


あなたのテストは、6 つの等しくない分岐のいずれもカバーしていません。 これらをカバーするには、ケース条件と等しくないが、同じハッシュ コードを持つ各ケースの文字列を見つける必要があります。それは可能ですが、間違いなく賢明ではありません...

おそらく、EclEmma のブランチ数は今後調整されるでしょう。

さらに、どのケースとも一致しないテスト ケースはないと思います (したがって、(暗黙の) デフォルト ケースはカバーされません)。

于 2015-01-18T21:50:47.097 に答える