我有一些使用try-with-resources的代码,在jacoco中,它只覆盖了一半。所有的源代码行都是绿色的,但我得到一个黄色的小符号,告诉我8个分支中只有4个被覆盖。
我无法弄清楚所有分支是什么,以及如何编写涵盖它们的代码。三个可能的地方抛出PipelineException
。这些是createStageList()
、Process Item()
和隐含的关闭()
我想不出任何其他案例,但我仍然只有8个案例中的4个。
有人能给我解释一下为什么它是8个中的4个,还有没有其他html" target="_blank">方法可以全部命中8个分支?我不擅长解密/读取/解释字节码,但也许你是……:)我已经看过了https://github.com/jacoco/jacoco/issues/82,但它和它引用的问题都没有多大帮助(除了注意到这是由于编译器生成的块)
嗯,就在我写完这篇文章的时候,我想到了哪些情况可能没有被我上面提到的测试...如果我答对了,我会发布一个答案。我相信这个问题和它的答案无论如何都会帮助某人。
编辑:没有,我没有找到。抛出运行时异常(不由catch块处理)不会覆盖更多的分支
没有真正的问题,但想在那里投入更多的研究。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%的行、指令和分支覆盖率:
分析: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创建了无法访问的路径。
我可以涵盖所有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;
}
}
我无法告诉您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只测