• jacoco 动态获取web项目覆盖率


      最近一个需求,在测试的时候需要获取代码覆盖率,通过jenkins目前无法解决,查阅jacoco官网觉得可以通过java agent的方式来处理这个问题。

      1、下载jacoco的工具类

        下载地址 http://www.jacoco.org/jacoco/index.html,直接下载最新的即可。

      2、将agent部署到服务器

        讲下的包中的/lib/jacocoagent拷贝到对应的服务器上,并修改tomcat 目录下的/bin/catalina.sh文件,在最后增加

    JAVA_OPTS="$JAVA_OPTS -javaagent:/yourdir/jacocoagent.jar=includes=yourpackage.*,output=tcpserver,port=8494,address=192.168.46.122"

        具体的参数可以参考官网,下面是官网给出的表格

    Option Description Default
    destfile Path to the output file for execution data. jacoco.exec
    append If set to true and the execution data file already exists, coverage data is appended to the existing file. If set to false, an existing execution data file will be replaced. true
    includes A list of class names that should be included in execution analysis. The list entries are separated by a colon (:) and may use wildcard characters (* and ?). Except for performance optimization or technical corner cases this option is normally not required. * (all classes)
    excludes A list of class names that should be excluded from execution analysis. The list entries are separated by a colon (:) and may use wildcard characters (* and ?). Except for performance optimization or technical corner cases this option is normally not required. empty (no excluded classes)
    exclclassloader A list of class loader names that should be excluded from execution analysis. The list entries are separated by a colon (:) and may use wildcard characters (* and ?). This option might be required in case of special frameworks that conflict with JaCoCo code instrumentation, in particular class loaders that do not have access to the Java runtime classes. sun.reflect.DelegatingClassLoader
    inclbootstrapclasses Specifies whether also classes from the bootstrap classloader should be instrumented. Use this feature with caution, it needs heavy includes/excludes tuning. false
    inclnolocationclasses Specifies whether also classes without a source location should be instrumented. Normally such classes are generated at runtime e.g. by mocking frameworks and are therefore excluded by default. false
    sessionid A session identifier that is written with the execution data. Without this parameter a random identifier is created by the agent. auto-generated
    dumponexit If set to true coverage data will be written on VM shutdown. The dump can only be written if either file is specified or the output is tcpserver/tcpclient and a connection is open at the time when the VM terminates. true
    output Output method to use for writing coverage data. Valid options are:
    • file: At VM termination execution data is written to the file specified in the destfile attribute.
    • tcpserver: The agent listens for incoming connections on the TCP port specified by the address and portattribute. Execution data is written to this TCP connection.
    • tcpclient: At startup the agent connects to the TCP port specified by the address and port attribute. Execution data is written to this TCP connection.
    • none: Do not produce any output.
    Please see the security considerations below.
    file
    address IP address or hostname to bind to when the output method is tcpserver or connect to when the output method istcpclient. In tcpserver mode the value "*" causes the agent to accept connections on any local address. loopback interface
    port Port to bind to when the output method is tcpserver or connect to when the output method is tcpclient. Intcpserver mode the port must be available, which means that if multiple JaCoCo agents should run on the same machine, different ports have to be specified. 6300
    classdumpdir Location relative to the working directory where all class files seen by the agent are dumped to. This can be useful for debugging purposes or in case of dynamically created classes for example when scripting engines are used. no dumps
    jmx If set to true the agent exposes functionality via JMX under the name org.jacoco:type=Runtime. Please see the security considerations below. false

       3、获取数据类

    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.net.InetAddress;
    import java.net.Socket;
    
    import org.jacoco.core.data.ExecutionDataWriter;
    import org.jacoco.core.runtime.RemoteControlReader;
    import org.jacoco.core.runtime.RemoteControlWriter;
    
    public class ExecutionDataClient {
        private static final String DESTFILE = "jacoco-client.exec";
    
        private static final String ADDRESS = "192.168.47.18";
    
        private static final int PORT = 8494;
    
        /**
         * Starts the execution data request.
         *
         * @param args
         * @throws IOException
         */
        public static void main(final String[] args) throws IOException {
            final FileOutputStream localFile = new FileOutputStream(DESTFILE);
            final ExecutionDataWriter localWriter = new ExecutionDataWriter(
                    localFile);
    
            // Open a socket to the coverage agent:
            final Socket socket = new Socket(InetAddress.getByName(ADDRESS), PORT);
            final RemoteControlWriter writer = new RemoteControlWriter(
                    socket.getOutputStream());
            final RemoteControlReader reader = new RemoteControlReader(
                    socket.getInputStream());
            reader.setSessionInfoVisitor(localWriter);
            reader.setExecutionDataVisitor(localWriter);
    
            // Send a dump command and read the response:
            writer.visitDumpCommand(true, false);
            reader.read();
    
            socket.close();
            localFile.close();
            System.out.println("ok");
        }
    
        private ExecutionDataClient() {
        }
    }

       4、生成报告类

    import java.io.File;
    import java.io.IOException;
    
    import org.jacoco.core.analysis.Analyzer;
    import org.jacoco.core.analysis.CoverageBuilder;
    import org.jacoco.core.analysis.IBundleCoverage;
    import org.jacoco.core.tools.ExecFileLoader;
    import org.jacoco.report.DirectorySourceFileLocator;
    import org.jacoco.report.FileMultiReportOutput;
    import org.jacoco.report.IReportVisitor;
    import org.jacoco.report.html.HTMLFormatter;
    
    public class ReportGenerator {
        private final String title;
    
        private final File executionDataFile;
        private final File classesDirectory;
        private final File sourceDirectory;
        private final File reportDirectory;
    
        private ExecFileLoader execFileLoader;
    
        /**
         * Create a new generator based for the given project.
         *
         * @param projectDirectory
         */
        public ReportGenerator(final File projectDirectory) {
            this.title = projectDirectory.getName();
            this.executionDataFile = new File(projectDirectory, "jacoco-client.exec");
            this.classesDirectory = new File(projectDirectory, "../web-interface/target/classes");
            this.sourceDirectory = new File(projectDirectory, "../web-interface/src/main/java");
            this.reportDirectory = new File(projectDirectory, "coveragereport");
        }
    
        /**
         * Create the report.
         *
         * @throws IOException
         */
        public void create() throws IOException {
    
            // Read the jacoco.exec file. Multiple data files could be merged
            // at this point
            loadExecutionData();
    
            // Run the structure analyzer on a single class folder to build up
            // the coverage model. The process would be similar if your classes
            // were in a jar file. Typically you would create a bundle for each
            // class folder and each jar you want in your report. If you have
            // more than one bundle you will need to add a grouping node to your
            // report
            final IBundleCoverage bundleCoverage = analyzeStructure();
    
            createReport(bundleCoverage);
    
        }
    
        private void createReport(final IBundleCoverage bundleCoverage)
                throws IOException {
    
            // Create a concrete report visitor based on some supplied
            // configuration. In this case we use the defaults
            final HTMLFormatter htmlFormatter = new HTMLFormatter();
            final IReportVisitor visitor = htmlFormatter
                    .createVisitor(new FileMultiReportOutput(reportDirectory));
    
            // Initialize the report with all of the execution and session
            // information. At this point the report doesn't know about the
            // structure of the report being created
            visitor.visitInfo(execFileLoader.getSessionInfoStore().getInfos(),
                    execFileLoader.getExecutionDataStore().getContents());
    
            // Populate the report structure with the bundle coverage information.
            // Call visitGroup if you need groups in your report.
            visitor.visitBundle(bundleCoverage, new DirectorySourceFileLocator(
                    sourceDirectory, "utf-8", 4));
    
            // Signal end of structure information to allow report to write all
            // information out
            visitor.visitEnd();
    
        }
    
        private void loadExecutionData() throws IOException {
            execFileLoader = new ExecFileLoader();
            execFileLoader.load(executionDataFile);
        }
    
        private IBundleCoverage analyzeStructure() throws IOException {
            final CoverageBuilder coverageBuilder = new CoverageBuilder();
            final Analyzer analyzer = new Analyzer(
                    execFileLoader.getExecutionDataStore(), coverageBuilder);
    
            analyzer.analyzeAll(classesDirectory);
    
            return coverageBuilder.getBundle(title);
        }
    
        /**
         * Starts the report generation process
         *
         * @param args
         *            Arguments to the application. This will be the location of the
         *            eclipse projects that will be used to generate reports for
         * @throws IOException
         */
        public static void main(final String[] args) throws IOException {
    //        for (int i = 0; i < args.length; i++) {
    //            final ReportGenerator generator = new ReportGenerator(new File(
    //                    args[i]));
    //            generator.create();
    //        }
    
            final ReportGenerator generator = new ReportGenerator(new File("/Users/tangrubei/projects/web-interface"));
            generator.create();
        }
    }

       5、启动tomcat,在测试执行完成后,执行前面的两个类,生成报告

  • 相关阅读:
    记录-java(jxl) Excel导入数据库
    记录--Gson、json转实体类、类转json
    记录--java获取网络资源(图片、音频等)保存本地
    记录--指定路径复制文件到另一个路径
    记录-java执行请求的URL
    记录-Hibernate+servlet实现简单的增、删、查、改
    我的学习之路_第二十八章_JQuery 和validator插件
    我的学习之路_第二十七章_jQuery
    我的学习之路_第二十六章_javaScript(2)
    我的学习之路_第二十五_javaScript
  • 原文地址:https://www.cnblogs.com/rubeitang/p/7607209.html
Copyright © 2020-2023  润新知