说明
为了保证测试的质量,我们需要关注代码的覆盖率。希望在每次执行单元测试之后会有对测试效果的评估标准。个人认为代码覆盖率报告是一个很好的评价标准。
我使用的工具为EclEmma,这是一个开源的软件测试工具,可以在编码过程中查看代码调用情况、也可以检测单覆盖率。
下面是关于代码覆盖率方面的整合。
EclEmma
这是一个Eclipse的插件,进行代码覆盖率的检查,可以在官方网站下载,这里使用的是2.3.2版本。此版本下载地址
-
安装
启动eclipse,Help->Install new Software... 然后按照下图操作,选择刚刚下载的软件包,按照提示完成操作!
安装成功之后会在java透视图中看到一个新的图标!可能需要在eclipse的Window->Show view中打开java->Coverage视图
- 使用
使用非常简单,通过Coverage运行java,junit程序,在Coverage视图中就会形成代码的执行覆盖率!
多次运行的结果可以很方便的Merged,这样可以把几次的运行结果共同形成代码覆盖率。
报告输出
EclEmma在Eclipse中可以直接导入和导出报告。
在具体工作中我希望每个人进行自己的单元测试代码编写,同时通过提交覆盖率报告!这就对报告的内容需要进行过滤,下面的代码是一个进行报告输出的工具
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import org.jacoco.core.analysis.Analyzer;
import org.jacoco.core.analysis.CoverageBuilder;
import org.jacoco.core.analysis.IBundleCoverage;
import org.jacoco.core.data.ExecutionDataReader;
import org.jacoco.core.data.ExecutionDataStore;
import org.jacoco.core.data.SessionInfo;
import org.jacoco.core.data.SessionInfoStore;
import org.jacoco.report.DirectorySourceFileLocator;
import org.jacoco.report.FileMultiReportOutput;
import org.jacoco.report.IReportVisitor;
import org.jacoco.report.html.HTMLFormatter;
/**
* 根据Coverage文件输出报告
*
* @author Linxm
*
*/
public class CoverageReportUtil {
/**
* Coverage文件:自己修改配置
*/
public static String fileName = "D:\\CoverageRepor\\Desktop.exec";
/**
* 输出报告的位置:自己修改配置
*/
public static String exportDir = "D:\\CoverageRepor\\report";
/**
* 报告包含的内容:自己修改配置
*/
public static String[] classNameArr = {
"com.aaa.common.utils.ConvertUtil"
,"com.aaa.common.utils.BeanMapUtil"
};
/**
* 工程路径:自己修改配置
*/
public static String workPath = "D:\\workspace\\project";
/**
* class文件的位置:通常不需要修改
*/
public static String classPath = workPath + "\\target\\classes";
/**
* 源码路径:通常不需要修改
*/
public static String srcPath = workPath + "\\src\\main\\java";
/**
* @param args
*/
public static void main(String[] args) {
try {
createReport();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void createReport() throws IOException {
// 读取监控结果
final FileInputStream fis = new FileInputStream(new File(fileName));
final ExecutionDataReader executionDataReader = new ExecutionDataReader(
fis);
// 执行数据信息
ExecutionDataStore executionDataStore = new ExecutionDataStore();
// 会话信息
SessionInfoStore sessionInfoStore = new SessionInfoStore();
executionDataReader.setExecutionDataVisitor(executionDataStore);
executionDataReader.setSessionInfoVisitor(sessionInfoStore);
while (executionDataReader.read()) {
}
fis.close();
// 分析结构
final CoverageBuilder coverageBuilder = new CoverageBuilder();
final Analyzer analyzer = new Analyzer(executionDataStore,
coverageBuilder);
// 传入监控时的Class文件目录,注意必须与监控时的一样
for(int i=0; i<classNameArr.length; i++){
File classesDirectory = new File(classPath + "/" + classNameArr[i].replace(".", "/") + ".class");
analyzer.analyzeAll(classesDirectory);
}
IBundleCoverage bundleCoverage = coverageBuilder.getBundle("Title");
// 输出报告
File reportDirectory = new File(exportDir); // 报告所在的目录
final HTMLFormatter htmlFormatter = new HTMLFormatter(); // HTML格式
final IReportVisitor visitor = htmlFormatter
.createVisitor(new FileMultiReportOutput(reportDirectory));
// 必须先调用visitInfo
List<SessionInfo> list = sessionInfoStore.getInfos();
visitor.visitInfo(list,
executionDataStore.getContents());
File sourceDirectory = new File(srcPath); // 源代码目录
// 遍历所有的源代码
// 如果不执行此过程,则在报告中只能看到方法名,但是无法查看具体的覆盖(因为没有源代码页面)
visitor.visitBundle(bundleCoverage, new DirectorySourceFileLocator(
sourceDirectory, "utf-8", 4));
// 执行完毕
visitor.visitEnd();
}
}
使用前先使用Eclipse导出覆盖率文件.exec,然后再使用本工具进行操作