运行 来自 gradle 的 jacoco 在已经检测的文件上

Running jacoco from gradle on already instrumented files

我正在为一个 java 项目尝试 jacoco 离线检测。

我创建了一个 hello world gradle java 项目并使用 jacoco 对其生成的 class 文件进行了检测。当我尝试对这些检测文件进行 运行 测试时。我收到以下错误。

java.lang.ClassCastException at CUTest.java:-1

反编译测试.class文件为

import org.junit.Test;

public class CUTest
{
  public CUTest()
  {
    arrayOfBoolean[0] = true;
  }

  @Test
  public void test()
  {
    boolean[] arrayOfBoolean = $jacocoInit();CUT localCUT1 = new CUT();arrayOfBoolean[1] = true;
    CUT c;
    c.meth();
    arrayOfBoolean[2] = true;
  }
}

检测源 .class 文件是

import java.io.PrintStream;

public class CUT
{
  public CUT()
  {
    arrayOfBoolean[0] = true;
  }

  public void meth()
  {
    boolean[] arrayOfBoolean = $jacocoInit();System.out.println("hello world");
    arrayOfBoolean[1] = true;
  }
}

jacoco 代理 jar 存在于 class路径上。我在 build.gradle.

中为此添加了一个测试编译依赖项

这里是源文件(不是反编译的class文件)

public class CUT {

    public void meth(){
        System.out.println("hello world");
    }

}

测试源

import static org.junit.Assert.*;

import org.junit.Test;

public class CUTest {

    @Test
    public void test() {
        CUT c = new CUT();
        c.meth();
    }

}

我使用 jacoco 检测 api 来检测编译这些 classes 后生成的 class 文件。 我想从这些 .class 文件(已经检测)生成 jacoco 报告。

这是 hello world 和 instrumentation 的项目 https://github.com/arpitgautam/jacoco-rat https://github.com/arpitgautam/jacoco

在提交 f4786df19a930726ebada97461d2a54ad463a4ec 时使用 https://github.com/arpitgautam/jacoco-rat 中的示例,如 README.md:

中所述
gradle build

Uncomment gradle.taskGraph.beforeTask from build.gradle

但在

期间

Take files in jacoco-rat\build\classes and instrument those using jacoco instrumentation api replace classes by the instrumented ones.

在提交 5e7ac40627eb4e2f0882ce143f5840ee9774af57 时使用您的 https://github.com/arpitgautam/jacoco 需要

change ROOT to absolute path of classes folder

这就是我的情况

public static final String ROOT = "/tmp/jacoco-rat/build/classes/";

得到

Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 32
    at java.lang.String.substring(String.java:1963)
    at com.exp.tools.JavaClassVisitor.createNewFolderName(JavaClassVisitor.java:69)

所以改为使用 JaCoCo command-line interface(将在下一版本中提供)来检测 类:

java -jar jacococli.jar instrument build/classes --dest build/instrumented

并替换原件:

rm -r build/classes
mv build/instrumented build/classes

然后再次执行Gradle作为gradle test --info,看到异常不是java.lang.ClassCastException,而是

java.lang.NoClassDefFoundError: org/jacoco/agent/rt/internal_8ff85ea/Offline
    at com.exp.tools.CUTest.$jacocoInit(CUTest.java)
    at com.exp.tools.CUTest.<init>(CUTest.java)

    Caused by:
    java.lang.ClassNotFoundException: org.jacoco.agent.rt.internal_8ff85ea.Offline
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        ... 2 more

引用 JaCoCo FAQ:

Why do I get an error "ClassNotFoundException: org.jacoco.agent[...]Offline"?

If you use offline instrumentation the instrumented classes get a direct dependency on the JaCoCo runtime. Therefore jacocoagent.jar of the same JaCoCo version must be on the classpath and accessible from by the instrumented classes.

根据http://www.jacoco.org/jacoco/trunk/doc/repo.html

Group ID    Artifact ID       Description
org.jacoco  org.jacoco.agent  API to get a local copy of the agent

Maven 存储库中的工件 org.jacoco:org.jacoco.agent 不是实际的代理,而是 API 来获取它。实际代理有分类器 runtime,即代替

testCompile group: 'org.jacoco', name: 'org.jacoco.agent', version: '0.7.9'

你绝对应该使用

testCompile group: 'org.jacoco', name: 'org.jacoco.agent', classifier: 'runtime', version: '0.7.9'

并修复 https://github.com/arpitgautam/jacoco 中的问题,其中您可能错误地使用 JaCoCo APIs 导致 java.lang.ClassCastException,或者使用已经开发的标准 JaCoCo 工具来进行检测,例如上面已经提到的即将推出的命令行界面,Ant 任务Maven 插件.