62

リソースでtryを使用するコードがいくつかありますが、jacocoでは半分しかカバーされていません。すべてのソース コード行は緑色ですが、8 つのブランチのうち 4 つだけがカバーされていることを示す小さな黄色のシンボルが表示されます。

ここに画像の説明を入力

すべてのブランチが何であるか、およびそれらをカバーするコードを記述する方法を理解するのに苦労しています。3ヶ所投げ可能PipelineException。これらはcreateStageList()processItem()あり、暗黙のclose()

  1. 例外をスローしない、
  2. から例外をスローするcreateStageList()
  3. から例外をスローするprocessItem()
  4. から例外をスローするclose()
  5. processItem()andから例外をスローするclose()

他のケースは考えられませんが、まだ 8 つのうち 4 つしかカバーしていません。

なぜ8つのうち4つなのか、8つすべてのブランチにヒットする理由を誰かが説明できますか? 私はバイトコードの復号化/読み取り/解釈に熟練していませんが、おそらくあなたは... :)私はすでにhttps://github.com/jacoco/jacoco/issues/82を見ましたが、それも問題もありませんそれは非常に助けを参照しています(これはコンパイラが生成したブロックによるものであることに注意することを除いて)

うーん、これを書き終えたとき、上記で述べたようにテストされていない可能性があるケースについて考えました...正しく理解できたら回答を投稿します。この質問とその答えは、いずれにしても誰かを助けると確信しています。

編集:いいえ、見つかりませんでした。(catch ブロックによって処理されない) RuntimeExceptions をスローしても、それ以上の分岐はカバーされませんでした。

4

6 に答える 6

57

Jacoco の正確な問題を説明することはできませんが、Try With Resources がどのようにコンパイルされているかを示すことはできます。基本的に、さまざまな時点でスローされた例外を処理するために、コンパイラによって生成された多くのスイッチがあります。

次のコードを取得してコンパイルすると

public static void main(String[] args){
    String a = "before";

    try (CharArrayWriter br = new CharArrayWriter()) {
        br.writeTo(null);
    } catch (IOException e){
        System.out.println(e.getMessage());
    }

    String a2 = "after";
}

そして逆アセンブルすると、

.method static public main : ([Ljava/lang/String;)V
    .limit stack 2
    .limit locals 7
    .catch java/lang/Throwable from L26 to L30 using L33
    .catch java/lang/Throwable from L13 to L18 using L51
    .catch [0] from L13 to L18 using L59
    .catch java/lang/Throwable from L69 to L73 using L76
    .catch [0] from L51 to L61 using L59
    .catch java/io/IOException from L3 to L94 using L97
    ldc 'before'
    astore_1
L3:
    new java/io/CharArrayWriter
    dup
    invokespecial java/io/CharArrayWriter <init> ()V
    astore_2
    aconst_null
    astore_3
L13:
    aload_2
    aconst_null
    invokevirtual java/io/CharArrayWriter writeTo (Ljava/io/Writer;)V
L18:
    aload_2
    ifnull L94
    aload_3
    ifnull L44
L26:
    aload_2
    invokevirtual java/io/CharArrayWriter close ()V
L30:
    goto L94
L33:
.stack full
    locals Object [Ljava/lang/String; Object java/lang/String Object java/io/CharArrayWriter Object java/lang/Throwable
    stack Object java/lang/Throwable
.end stack
    astore 4
    aload_3
    aload 4
    invokevirtual java/lang/Throwable addSuppressed (Ljava/lang/Throwable;)V
    goto L94
L44:
.stack same
    aload_2
    invokevirtual java/io/CharArrayWriter close ()V
    goto L94
L51:
.stack same_locals_1_stack_item
    stack Object java/lang/Throwable
.end stack
    astore 4
    aload 4
    astore_3
    aload 4
    athrow
L59:
.stack same_locals_1_stack_item
    stack Object java/lang/Throwable
.end stack
    astore 5
L61:
    aload_2
    ifnull L91
    aload_3
    ifnull L87
L69:
    aload_2
    invokevirtual java/io/CharArrayWriter close ()V
L73:
    goto L91
L76:
.stack full
    locals Object [Ljava/lang/String; Object java/lang/String Object java/io/CharArrayWriter Object java/lang/Throwable Top Object java/lang/Throwable
    stack Object java/lang/Throwable
.end stack
    astore 6
    aload_3
    aload 6
    invokevirtual java/lang/Throwable addSuppressed (Ljava/lang/Throwable;)V
    goto L91
L87:
.stack same
    aload_2
    invokevirtual java/io/CharArrayWriter close ()V
L91:
.stack same
    aload 5
    athrow
L94:
.stack full
    locals Object [Ljava/lang/String; Object java/lang/String
    stack 
.end stack
    goto L108
L97:
.stack same_locals_1_stack_item
    stack Object java/io/IOException
.end stack
    astore_2
    getstatic java/lang/System out Ljava/io/PrintStream;
    aload_2
    invokevirtual java/io/IOException getMessage ()Ljava/lang/String;
    invokevirtual java/io/PrintStream println (Ljava/lang/String;)V
L108:
.stack same
    ldc 'after'
    astore_2
    return
.end method

バイトコードを話さない人にとって、これは次の疑似 Java とほぼ同じです。バイトコードは実際には Java 制御フローに対応していないため、goto を使用する必要がありました。

ご覧のとおり、抑制された例外のさまざまな可能性を処理する多くのケースがあります。これらすべてのケースをカバーできるのは合理的ではありません。実際、goto L59最初の try ブロックの分岐には到達できません。最初の catch Throwable がすべての例外をキャッチするからです。

try{
    CharArrayWriter br = new CharArrayWriter();
    Throwable x = null;

    try{
        br.writeTo(null);
    } catch (Throwable t) {goto L51;}
    catch (Throwable t) {goto L59;}

    if (br != null) {
        if (x != null) {
            try{
                br.close();
            } catch (Throwable t) {
                x.addSuppressed(t);
            }
        } else {br.close();}
    }
    break;

    try{
        L51:
        x = t;
        throw t;

        L59:
        Throwable t2 = t;
    } catch (Throwable t) {goto L59;}

    if (br != null) {
        if (x != null) {
            try{
                br.close();
            } catch (Throwable t){
                x.addSuppressed(t);
            }
        } else {br.close();}
    }
    throw t2;
} catch (IOException e) {
    System.out.println(e)
}
于 2013-06-28T03:23:15.433 に答える
1

私はこのようなもので同様の問題を抱えていました:

try {
...
} finally {
 if (a && b) {
  ...
 }
}

8 つのブランチのうち 2 つがカバーされていないと不平を言いました。これをやってしまった:

try {
...
} finally {
 ab(a,b);
}

void ab(a, b) {
 if (a && b) {
...
 }
}

他に変更はなく、現在100%に達しています....

于 2014-08-29T18:31:44.880 に答える