通过代码方式使用Jacoco远程统计tomcat服务的代码覆盖率
1)修改远程tomcat下的bin/catalina.sh中JAVA_OPTS的配置
----------------------------------------------------------------
# -javaagent: 的后面跟jacoco的安装路径
# includes= 选项,选择你要覆盖率的服务
# port= 选项,选择你要打开的端口
# address= 选项,tomcat服务所在机器的ip地址(如果想在跟tomcat服务同一台机器上执行ant任务的话,需要改为127.0.0.1)
----- Execute The Requested Command ------------------------------
JAVA_OPTS="-javaagent:/path/to/your/jacoco_0.8.5/lib/jacocoagent.jar=includes=com.*,output=tcpserver,port=8893,address=10.81.14.77"
2)在开发环境pom.xml中引入jacoco的jar包
<!--使用jacoco对web工程生成全部的覆盖率报告--> <dependency> <groupId>org.jacoco</groupId> <artifactId>org.jacoco.core</artifactId> <version>0.8.5</version> </dependency> <dependency> <groupId>org.jacoco</groupId> <artifactId>org.jacoco.report</artifactId> <version>0.8.5</version> </dependency>
3)调用代码实现
package com.wangfg.jacoco; import org.jacoco.core.data.ExecutionDataWriter; import org.jacoco.core.runtime.RemoteControlReader; import org.jacoco.core.runtime.RemoteControlWriter; import org.junit.Test; import java.io.FileOutputStream; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; /** * 用于生成xxx.exec数据的程序 */ public class ExecutionDataClient { private static final String DESTFILE = "jacoco-client.exec"; private static final String ADDRESS = "127.0.0.1"; private static final int PORT = 8044; /** * Starts the execution data request. * * @throws IOException */ @Test public void test() 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(); } }
package com.wangfg.jacoco; 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; import org.junit.Test; import java.io.File; import java.io.IOException; public class ReportGenerator { private final String title = "jacoco-demo"; private final File executionDataFile = new File("C:\\Users\\Administrator\\Downloads\\jacoco\\jacoco-client.exec"); private final File classesDirectory = new File("C:\\Users\\Administrator\\Downloads\\jacoco\\target\\classes\\com\\wangfg\\jacoco\\controller"); private final File sourceDirectory= new File("C:\\Users\\Administrator\\Downloads\\jacoco\\src"); private final File reportDirectory = new File("C:\\Users\\Administrator\\Downloads\\jacoco\\coveragereport"); private ExecFileLoader execFileLoader; /** * Create the report. * * @throws IOException */ @Test public void test() 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(IBundleCoverage bundleCoverage) throws IOException { // Create a concrete report visitor based on some supplied // configuration. In this case we use the defaults HTMLFormatter htmlFormatter = new HTMLFormatter(); 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 { CoverageBuilder coverageBuilder = new CoverageBuilder(); Analyzer analyzer = new Analyzer( execFileLoader.getExecutionDataStore(), coverageBuilder); analyzer.analyzeAll(classesDirectory); return coverageBuilder.getBundle(title); } }
4)分别执行以上代码即可得到远程代码的覆盖率。