java - संसाधनों के साथ प्रयास करने के लिए 8 शाखाएं-जैकोको कवरेज संभव है?




code-coverage bytecode (4)

कोई वास्तविक सवाल नहीं है, लेकिन वहां और अधिक शोध फेंकना चाहता था। tl; dr = ऐसा लगता है कि आप अंततः प्रयास के लिए 100% कवरेज प्राप्त कर सकते हैं, लेकिन संसाधन के साथ प्रयास नहीं कर सकते हैं।

समझा जा सकता है कि पुराने स्कूल के प्रयास-अंत में और जावा 7 प्रयास-संसाधनों के बीच एक अंतर है। वैकल्पिक दृष्टिकोणों का उपयोग करके एक ही चीज़ दिखाते हुए दो समकक्ष उदाहरण यहां दिए गए हैं।

ओल्ड स्कूल उदाहरण (एक कोशिश-अंत दृष्टिकोण):

final Statement stmt = conn.createStatement();
try {
    foo();
    if (stmt != null) {
        stmt.execute("SELECT 1");
    }
} finally {
    if (stmt != null)
        stmt.close();
}

जावा 7 उदाहरण (एक कोशिश-संसाधन-संसाधन दृष्टिकोण):

try (final Statement stmt = conn.createStatement()) {
    foo();
    if (stmt != null) {
        stmt.execute("SELECT 1");
    }
}

विश्लेषण: पुराने स्कूल का उदाहरण:
जैकोको 0.7.4.201502262128 और जेडीके 1.8.0_45 का उपयोग करके, मैं निम्नलिखित 4 परीक्षणों का उपयोग करके ओल्ड स्कूल उदाहरण पर 100% लाइन, निर्देश और शाखा कवरेज प्राप्त करने में सक्षम था:

  • मूल ग्रीस पथ (स्टेटमेंट शून्य नहीं है, और निष्पादित () सामान्य रूप से प्रयोग किया जाता है)
  • निष्पादित () अपवाद फेंकता है
  • foo () अपवाद फेंकता है और कथन शून्य के रूप में वापस आ गया
  • बयान के रूप में वापस आ गया
जैकोको 'कोशिश' (शून्य जांच पर) के अंदर 2 शाखाओं को इंगित करता है और अंत में 4 (शून्य जांच पर)। सभी पूरी तरह से कवर कर रहे हैं।

विश्लेषण: जावा -7 उदाहरण:
यदि जावा 7 स्टाइल उदाहरण के खिलाफ समान 4 परीक्षण चलते हैं, तो जैकोको इंगित करता है कि कोशिश में 6/8 शाखाएं शामिल हैं (स्वयं कोशिश करें) और 2/2 नल-चेक पर। मैंने कवरेज बढ़ाने के लिए कई अतिरिक्त परीक्षणों की कोशिश की, लेकिन मुझे 6/8 से बेहतर पाने का कोई तरीका नहीं मिला। जैसा कि अन्य ने संकेत दिया है, जावा -7 उदाहरण के लिए डिकंपिल्ड कोड (जिसे मैंने भी देखा) सुझाव देता है कि जावा कंपाइलर प्रयास-संसाधन के लिए पहुंचने योग्य सेगमेंट उत्पन्न कर रहा है। जैकोको रिपोर्टिंग (सटीक) है कि ऐसे सेगमेंट मौजूद हैं।

अद्यतन: जावा 7 कोडिंग शैली का उपयोग करके, आप Java7 JRE का उपयोग करके 100% कवरेज प्राप्त कर सकते हैं (नीचे मैटिया प्रतिक्रिया देखें)। हालांकि, जावा 8 जेआरई के साथ जावा 7 कोडिंग शैली का उपयोग करके, मुझे विश्वास है कि आप 6/8 शाखाओं को कवर करेंगे। वही कोड, बस अलग जेआरई। ऐसा लगता है कि जावा 8 के साथ दो जेआरई के बीच बाइट कोड अलग-अलग बनाया जा रहा है, जो पहुंचने योग्य मार्ग बना रहा है।

मेरे पास कुछ कोड है जो संसाधनों के साथ प्रयास करता है और जैकोको में यह आधे कवर के रूप में आ रहा है। सभी स्रोत कोड लाइनें हरे रंग की हैं, लेकिन मुझे थोड़ा पीला प्रतीक मिलता है जो मुझे बता रहा है कि केवल 8 में से 4 शाखाएं शामिल हैं।

मुझे यह पता लगाने में परेशानी हो रही है कि सभी शाखाएं क्या हैं, और उन्हें कवर करने वाले कोड को कैसे लिखना है। PipelineException फेंकने के तीन संभावित स्थान। ये createStageList() , createStageList() processItem() और अंतर्निहित close()

  1. कोई अपवाद नहीं फेंक रहा है,
  2. createStageList() से अपवाद फेंकना
  3. processItem() से अपवाद फेंकना
  4. close() से अपवाद फेंकना close()
  5. processItem() और close() से अपवाद फेंकना

मैं किसी अन्य मामले के बारे में नहीं सोच सकता, फिर भी मेरे पास अभी भी 8 में से 4 शामिल हैं।

क्या कोई मुझे समझा सकता है कि यह 8 में से 4 क्यों है और क्या सभी 8 शाखाओं को मारने के लिए वैसे भी है? मैं बाइट कोड को decyrpting / पढ़ने / व्याख्या करने के साथ कुशल नहीं हूँ, लेकिन शायद आप हैं ... :) मैंने पहले ही https://github.com/jacoco/jacoco/issues/82 देखा है, लेकिन न तो यह और न ही समस्या यह संदर्भ बहुत मदद करता है (यह नोट करने के अलावा कि यह संकलक उत्पन्न ब्लॉक के कारण है)

हम्म, जैसे ही मैंने इसे लिखना समाप्त किया था, मैंने सोचा था कि किस मामले में मैंने ऊपर उल्लेख किया है, उसके द्वारा परीक्षण नहीं किया जा सकता है ... यदि मैं इसे सही समझता हूं तो मैं एक उत्तर पोस्ट करूंगा। मुझे यकीन है कि यह सवाल है और इसका जवाब किसी भी मामले में किसी की मदद करेगा।

संपादित करें: नहीं, मुझे यह नहीं मिला। रनटाइम अपवाद (पकड़ने वाले ब्लॉक द्वारा नियंत्रित नहीं) को फेंकने से कोई और शाखाएं शामिल नहीं हुईं


खैर मैं आपको नहीं बता सकता कि जैको के साथ क्या समस्या है, लेकिन मैं आपको दिखा सकता हूं कि संसाधनों के साथ प्रयास कैसे संकलित किया जाता है। असल में, विभिन्न बिंदुओं पर फेंकने वाले अपवादों को संभालने के लिए बहुत सारे कंपाइलर जेनरेट स्विच होते हैं।

अगर हम निम्नलिखित कोड लेते हैं और इसे संकलित करते हैं

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

उन लोगों के लिए जो बाइटकोड नहीं बोलते हैं, यह लगभग छद्म जावा के बराबर है। मुझे गेटोस का उपयोग करना पड़ा क्योंकि बाइटकोड वास्तव में जावा नियंत्रण प्रवाह से मेल नहीं खाता है।

जैसा कि आप देख सकते हैं, दबाने वाले अपवादों की विभिन्न संभावनाओं को संभालने के लिए कई मामले हैं। इन सभी मामलों को कवर करने में सक्षम होना उचित नहीं है। वास्तव में, पहली कोशिश ब्लॉक पर goto L59 शाखा पहुंचना असंभव है, क्योंकि पहली पकड़ थ्रोबल सभी अपवादों को पकड़ लेगी।

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)
}

जैकोको ने हाल ही में इस मुद्दे को ठीक किया है, रिलीज 0.8.0 (2018/01/02)

"रिपोर्टों के निर्माण के दौरान विभिन्न कंपाइलर जेनरेट किए गए कलाकृतियों को फ़िल्टर किया जाता है, अन्यथा अनावश्यक और कभी-कभी असंभव चालों की आंशिक या मिस्ड कवरेज नहीं होती है:

  • कोशिश-के-संसाधन विवरणों के लिए बाइटकोड का हिस्सा (गिटहब # 500)। "

http://www.jacoco.org/jacoco/trunk/doc/changes.html


मुझे इस तरह के कुछ के साथ एक समान समस्या थी:

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

यह शिकायत की गई कि 8 में से 2 शाखाएं शामिल नहीं थीं। ऐसा करने के लिए समाप्त हो गया:

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

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

कोई अन्य बदलाव नहीं और अब मैं 100% तक पहुंच गया ....







try-with-resources