当前位置: 首页 > 知识库问答 >
问题:

8个分支机构尝试资源-雅各科覆盖可能吗?

符棋
2023-03-14

我有一些使用try-with-resources的代码,在jacoco中,它只覆盖了一半。所有的源代码行都是绿色的,但我得到一个黄色的小符号,告诉我8个分支中只有4个被覆盖。

我无法弄清楚所有分支是什么,以及如何编写涵盖它们的代码。三个可能的地方抛出PipelineException。这些是createStageList()Process Item()和隐含的关闭()

  1. 不抛出任何异常,

我想不出任何其他案例,但我仍然只有8个案例中的4个。

有人能给我解释一下为什么它是8个中的4个,还有没有其他html" target="_blank">方法可以全部命中8个分支?我不擅长解密/读取/解释字节码,但也许你是……:)我已经看过了https://github.com/jacoco/jacoco/issues/82,但它和它引用的问题都没有多大帮助(除了注意到这是由于编译器生成的块)

嗯,就在我写完这篇文章的时候,我想到了哪些情况可能没有被我上面提到的测试...如果我答对了,我会发布一个答案。我相信这个问题和它的答案无论如何都会帮助某人。

编辑:没有,我没有找到。抛出运行时异常(不由catch块处理)不会覆盖更多的分支

共有3个答案

南宫森
2023-03-14

没有真正的问题,但想在那里投入更多的研究。tl; dr=看起来你可以实现100%的最终尝试覆盖率,但不能实现资源尝试覆盖率。

可以理解,老式的try finally和Java7的try with resources之间存在差异。这里有两个等价的例子,用不同的方法展示了相同的事情。

老派的例子(最后一次尝试的方法):

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

Java7示例(一种尝试资源的方法):

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

分析:老派示例:
使用Jacoco 0.7.4.201502262128和JDK 1.8.0_45,我能够通过以下4个测试在老派示例上获得100%的行、指令和分支覆盖率:

  • 基本润滑脂路径(语句不为空,执行()正常执行)
  • 执行()抛出异常
  • foo()抛出异常AND语句返回为null
  • 语句返回为null

分析:java-7示例:如果对Java7样式示例运行相同的4个测试,jacoco表示覆盖了6/8个分支(在try本身上),2/2个分支覆盖了try内的null检查。我尝试了一些额外的测试来增加覆盖率,但我找不到比6/8更好的方法。正如其他人所指出的,java-7示例的反编译代码(我也看过)表明java编译器正在为try-with-resource生成无法访问的段。Jacoco(准确地)报告了此类细分市场的存在。

更新:使用Java7编码风格,如果使用Java7 JRE,您可能能够获得100%的覆盖率(请参阅下面的Matyas回复)。然而,使用Java7编码风格和Java8 JRE,我相信您将达到所涵盖的6/8分支。相同的代码,只是不同的JRE。看起来两个JRE之间的字节码创建方式不同,Java8创建了无法访问的路径。

林运浩
2023-03-14

我可以涵盖所有8个分支,所以我的答案是肯定的。看看下面的代码,这只是一个快速的尝试,但它是有效的(或者看看我的github:https://github.com/bachoreczm/basicjava和'try with Resources'包,在那里你可以找到,try-with-Resources是如何工作的,见'Explan ationOfTryWitResources'类):

import java.io.ByteArrayInputStream;
import java.io.IOException;

import org.junit.Test;

public class TestAutoClosable {

  private boolean isIsNull = false;
  private boolean logicThrowsEx = false;
  private boolean closeThrowsEx = false;
  private boolean getIsThrowsEx = false;

  private void autoClose() throws Throwable {
    try (AutoCloseable is = getIs()) {
        doSomething();
    } catch (Throwable t) {
        System.err.println(t);
    }
  }

  @Test
  public void test() throws Throwable {
    try {
      getIsThrowsEx = true;
      autoClose();
    } catch (Throwable ex) {
      getIsThrowsEx = false;
    }
  }

  @Test
  public void everythingOk() throws Throwable {
    autoClose();
  }

  @Test
  public void logicThrowsException() {
    try {
      logicThrowsEx = true;
      everythingOk();
    } catch (Throwable ex) {
      logicThrowsEx = false;
    }
  }

  @Test
  public void isIsNull() throws Throwable {
    isIsNull = true;
    everythingOk();
    isIsNull = false;
  }

  @Test
  public void closeThrow() {
    try {
      closeThrowsEx = true;
      logicThrowsEx = true;
      everythingOk();
      closeThrowsEx = false;
    } catch (Throwable ex) {
    }
  }

  @Test
  public void test2() throws Throwable {
    try {
      isIsNull = true;
      logicThrowsEx = true;
      everythingOk();
    } catch (Throwable ex) {
      isIsNull = false;
      logicThrowsEx = false;
    }
  }

  private void doSomething() throws IOException {
    if (logicThrowsEx) {
      throw new IOException();
    }
  }

  private AutoCloseable getIs() throws IOException {
    if (getIsThrowsEx) {
      throw new IOException();
    }
    if (closeThrowsEx) {
      return new ByteArrayInputStream("".getBytes()) {

        @Override
        public void close() throws IOException {
          throw new IOException();
        }
      };
    }
    if (!isIsNull) {
      return new ByteArrayInputStream("".getBytes());
    }
    return null;
  }
}
步炯
2023-03-14

我无法告诉您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。我不得不使用gotos,因为字节码并不真正对应Java控制流。

如您所见,有很多情况可以处理各种被抑制异常的可能性。不能涵盖所有这些情况是不合理的。事实上,第一个try块上的转到L59分支是不可能到达的,因为第一个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)
}
 类似资料:
  • 我正在尝试使用SonarQube扫描仪(版本3.1.0.1141)分析java代码。 声纳Qube版本 : 5.6.6 声纳Java插件版本: 4.12.0.11033 哈科版本 : 0.8.0 我已经用这些属性填充了声纳项目属性: 而Jacoco报告给我一个类的结果: 覆盖率:84% 分支机构覆盖率:71% 错过:9 复杂性:24 错过:6 行数:69 错过:0 方法:8 错过:0 课程:1 S

  • 当我运行mvn干净测试时,我希望覆盖输出被写入目标/覆盖报告,但是当我打开index.html构建后它是空的。 我检查了以下内容,jacoco.exec文件存在,其中有一组类名-在覆盖率html中有一个链接“Sessions ”,当我单击它时,我看到一组我的类似乎已经被执行-当我运行maven命令时,我没有看到错误或警告 我很困惑为什么报告是空的。从我看到的所有例子来看,这似乎应该行得通。我错过了

  • 我使用Gradle 6.3和Jacoco来编译、测试和显示覆盖率报告。但是我不明白为什么它抱怨“两个分支中的一个丢失了”,根本没有分支: 下面是完整的静态编程语言数据类: 如果幕后有树枝,它们是什么?我该如何覆盖它们?

  • 主要内容:如何计算分支覆盖范围?分支覆盖技术用于覆盖控制流图的所有分支。它至少涵盖决策点的每个条件的所有可能结果(真和假)。分支覆盖技术是一种白盒测试技术,可确保每个决策点的每个分支都必须执行。 然而,分支覆盖技术和决策覆盖技术非常相似,但两者之间存在关键差异。决策覆盖技术涵盖每个决策点的所有分支,而分支测试涵盖代码的每个决策点的所有分支。 换句话说,分支覆盖遵循决策点和分支覆盖边缘。许多不同的指标可用于查找分支覆盖范围和决策覆

  • 在我的Android项目中,雅各布不包括机器人测试。我可以得到机器人浓缩咖啡和junit测试覆盖与哈科没有任何问题。 我确实看到了有关此问题的其他问题,所有答案都是升级jaco版本。我使用的是最新的雅各科版本 0.7.9 这是我的项目main 应用程序模块构建梯度。

  • Jacoco 是否为 API 的集成测试提供代码覆盖率?也就是说,我有一个在本地运行的应用程序实例,并且我有集成测试,其中我命中了正在运行的应用程序实例提供的api。在这种情况下,我是否可以使用 Jacoco 来获取在集成测试运行时覆盖了多少行正在运行的应用程序实例? 我已经尝试了Jacoco的maven插件的准备代理集成和报告集成目标。但它们给出的代码覆盖率为 0。我认为这是因为jacoco只测