经常有人问这样的问题:“我们在做单元测试,那测试覆盖率要到多少才行?”。答案其实很简答,“作为指标的测试覆盖率都是没有用处的。”
Martin Fowler(重构那本书的作者)曾经写过一篇博客来讨论这个问题,他指出:把测试覆盖作为质量目标没有任何意义,而我们应该把它作为一种发现未被测试覆盖的代码的手段。
分析未覆盖部分的代码,从而反推在前期测试设计是否充分,没有覆盖到的代码是否是测试设计的盲点,为什么没有考虑到?需求/设计不够清晰,测试设计的理解有误,工程方法应用后的造成的策略性放弃等等,之后进行补充测试用例设计。
检测出程序中的废代码,可以逆向反推在代码设计中思维混乱点,提醒设计/开发人员理清代码逻辑关系,提升代码质量。
代码覆盖率高不能说明代码质量高,但是反过来看,代码覆盖率低,代码质量不会高到哪里去,可以作为测试自我审视的重要工具之一。
以上都是我抄的,用于装逼
今天主要分享我如何把覆盖率落地到实际测试过程中。以下是我学习过的帖子
Jacoco 统计 Android 代码覆盖率 [instrument 方式]
浅谈代码覆盖率
Android 增量代码测试覆盖率工具
jacoco jenkins 插件
看了很多的帖子,学习了很多内容,在看到 jenkins 插件的时候才想如何串起来整个流程。 我的整个流程分为 4 小块
目前公司测试情况,还是多数手工测试为主,这时候其实可以很好的收集数据的时机,sdk 只要分为 debug 和 release 版本即可做到无缝的构建切换,无任何副作用。
数据收集的时机可考虑以下几种情况:
dump 数据的代码,社区里面很多了,重要是把文件上传了,且需要记录对应的代码分支,例如这个:
public static void generateEcFile(boolean isNew) {
// String DEFAULT_COVERAGE_FILE_PATH = NLog.getContext().getFilesDir().getPath().toString() + "/coverage.ec";
Log.d(TAG, "生成覆盖率文件: " + DEFAULT_COVERAGE_FILE_PATH);
OutputStream out = null;
File mCoverageFilePath = new File(DEFAULT_COVERAGE_FILE_PATH);
try {
if (isNew && mCoverageFilePath.exists()) {
Log.d(TAG, "JacocoUtils_generateEcFile: 清除旧的ec文件");
mCoverageFilePath.delete();
}
if (!mCoverageFilePath.exists()) {
mCoverageFilePath.createNewFile();
}
out = new FileOutputStream(mCoverageFilePath.getPath(), true);
Object agent = Class.forName("org.jacoco.agent.rt.RT")
.getMethod("getAgent")
.invoke(null);
out.write((byte[]) agent.getClass().getMethod("getExecutionData", boolean.class)
.invoke(agent, false));
Log.d(TAG,"写入" + DEFAULT_COVERAGE_FILE_PATH + "完成!" );
} catch (Exception e) {
Log.e(TAG, "generateEcFile: " + e.getMessage());
Log.e(TAG,e.toString());
} finally {
if (out == null)
return;
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务端主要的作用是保持覆盖率数据,同时进行相同的 exec 文件进行替换操作,分析对应的文件可以得知每次 app 初始化的时候会随机产生一个 seesion id,解析方式如下:
BufferedInputStream inputStream = null;
final SessionInfoStore sessionInfoStore = new SessionInfoStore();
final ExecutionDataStore executionDataStore = new ExecutionDataStore();
try {
inputStream = new BufferedInputStream(file.getInputStream());
final ExecutionDataReader reader = new ExecutionDataReader(inputStream);
reader.setSessionInfoVisitor(sessionInfoStore);
reader.setExecutionDataVisitor(executionDataStore);
reader.read();
}catch (Exception e) {
log.error("parse exec file fail", e);
return Result.Failure("parse exec file fail, please check it .");
}finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
}
}
}
if (sessionInfoStore.isEmpty()) {
return Result.Failure("exec file not valid, can't found sessionid");
}
final String sessionId = sessionInfoStore.getInfos().get(0).getId();
使用多参数构建方式,管理后台选择对应的 jacoco 覆盖率数据,发给 jenkins。
jenkins 主要事物:
下载代码分享
#!/bin/bash
echo "downloading ExecFiles"
echo "$ExecFiles"
fileUrl="$ExecFiles"
fileUrl=${fileUrl//,/ };
fileUrls=($fileUrl);
jacocoDir="$WORKSPACE""/jacoco"
if test -e $jacocoDir
then
echo '文件夹已存在,删掉'
rm -rf "$jacocoDir"
mkdir $jacocoDir
else
mkdir $jacocoDir
fi
echo "jacocoDir: $jacocoDir"
cd $jacocoDir
for url in ${fileUrls[*]}
do
curl -O $url
done
echo "Done !!!!!!"
这时候你会发现为毛一点增量也没有说?
其实到这里你应该发现,在数据收集的时候已经有对应的覆盖率文件的分支了,这时候只需要借助我上面发的插件,下载你想要进行增加覆概率检查的分支代码即可。
支持这个的主要理论还有就是 jacoco 本身支持多份 exec 文件合并生成覆盖率报告。
好了,我的装逼到此结束。