基于业务测试的增量代码覆盖率实现

 

前言:本文主要实现的功能是代码增量覆盖率,且基于覆盖率已实现,可拿到全量覆盖率结果的情况下,给出的增量代码覆盖率方法实现,虽然各类语言有差别,但是实现的基本思路都是一致的

名词解释:

增量代码:增量代码指的是相对于master一个分支新增的代码,通常对应我们的测试分支,可以通过分支的diff得出

覆盖率:指的是请求过程中,覆盖哪些行代码,本文主要针对行代码覆盖率进行阐述,不适用与方法覆盖率

语言:目前主流的语言,JAVA可以通过JACOCO实现覆盖率,GO通过SDK即可实现,我在实现的过程中是基于PHP语言做的,需要使用XDEBUG插件

 

1,基本原理

计算覆盖率第一步需要拿到diff,即你的分支diff,在拿到分支diff后,我们要通过覆盖率的结果文件与diff中的代码进行对比过滤,如果覆盖率的结果在本次diff中,说明本次测试覆盖了该行

流程图:

2,实现难点

a:如何计算历史覆盖率

b:如果是主干上线,在master不断迭代的情况下会产生很多已上线,但不属于本次测试范围的代码,此时应该以什么为基准与分支进行diff

c:如果同一分支进行两次提交,第一次被覆盖的行收到了第二次提交的影响,但是处理历史覆盖率时,这部分代码应该如何进行统计

3,diff计算方法

     在做diff时,首先要了解一些git的分区概念以及常用的命令,这里引用这篇文章https://www.cnblogs.com/kisun168/p/11408346.html,如果你们有代码服务的平台(封装的gitlab接口,通过接口实现一些常见的git操作),一般可以通过接口调用解决,但是如果没有代码服务平台,此时就需要借助.git目录来完成增量代码的计算,由于大家不一定都有代码服务,本文会以基本的git命令来完成这些接口实现‘

注意:在完成以下操作时,应该更新本地仓库,使本地仓库与远程仓库保持一致,否则会造成diff出现误差,关于git的操作,我们不会考虑git commit的撤销情况,即认为commit是不断增加的,commit不会被删除

a:

获取一个分支最新的commitid  eg:bb4f92a7d4cbafb67d259edea5a1fa2dd6b4cc7a

git rev-parse HEAD

获取short commit id    eg:bb4f92a

git rev-parse --short HEAD

b:

如果master有提交,而此时你本地的分支又没有合并master,此时应该怎样diff呢

此处需要了解一个git命令

git merge-base [-a|--all] <commit> <commit>…​

原理图

c:我们通过git diff commit1 commit2来获取diff内容 commit1是 git merge-base计算出来的公共commitid  commit2是这个分支最新的commit,此时我们即可获得两个分支的diff,同时忽略掉来master更新的影响

结论1:此时我们获得了分支diff的方法

d:在拿到计算方法以后,我们如何计算在此次diff中都修改了哪些内容呢,可以参考下图

diff --git a/serivce/executebyapi.py b/serivce/executebyapi.py
index 20dc848..c02b633 100644
--- a/serivce/executebyapi.py
+++ b/serivce/executebyapi.py
@@ -201,6 +201,7 @@ def executeII(commitid,branch,moduleid):
     #将覆盖率数据赋值到tempdiffcontent,然后进行插入操作
     for item in coverageresult.keys():
         coveragedline = coverageresult[item]
+        coveragedline = [str(x) for x in coveragedline]
         for i in range(len(changelist)):
             tempdata = changelist[i]
             diffclass = tempdata['filename']
@@ -214,7 +215,7 @@ def executeII(commitid,branch,moduleid):
         filename = getattr(temdata,'filename')
 
         coverageline = getattr(temdata,'coveragedline')
-        
+
         for i in range(len(changelist)):
             data = changelist[i]

图中是常见的一个difflog日志,如何能从这个log中拿到我们想要获取的信息呢,如果做行覆盖率,那么我们此时肯定关心这个diff都影响到了哪些行,哪些行代表新增的

概念明确:此处我们来细化一些difflog的含义

规则1:图中的-代表仅出现在commit1中的内容,图中的+代表仅出现在commit2中的内容

第一行:是第一次提交与第二次提交对应的两个文件

第三行:commit1的文件

第四行:commit2对应commit1的文件

第五行:@@ -201,6 +201,7 @@  这串数字代表的含义是,从a文件开始的201行开始计算(包括201行)向下数6行的内容有改动,这段改动对应到新文件是  b文件的201行,(包括201行)向下数7行有改动(这里需要我们注意的两个点是,1:201行指的是从 “#将覆盖率数据赋值到“  那一行开始计算的,并不包括def executeII这一行,该行提示的通常是哪个方法或者哪个类,2,为什么对应到新文件是7行,因为diff中有一行+号,在计算新提交对应改动的范围是,必须算上这一行,但是老提交不必计算,这就是根据规则1得来的+标记的内容是仅出现在新提交中的内容) 通常,返回的这个数据就代表了两次提交都改动了哪些行

解析log:此时我们会认为,这次最新的提交b文件的204,218行是这次新增的内容,如果这两行也在覆盖率中,那么就代表被测试覆盖了

结论二:此时我们获得了计算两次提交改动了哪些行的方法

通过上述方法,我们可以总结归纳出一些结论,这些结论在我们进行计算历史覆盖率时是有帮助的

a:在git中一行代码存在的三种情况

    被删除:只存在于原文件中

    被改动:将原行删除,对修改后的代码重新标记,只存在于新文件中

    行号变动:可以理解为,在这一行的上边新增或删除了代码,导致了这行代码的行号是变动的,实际这一行的代码内容我们通过diff是没有办法确定是否改动了,只要这一行被标记了-,此时我们就认为这一行需要重新测试覆盖,因为我们不能确定他的内容改没改

b:在git中-,+相连时的含义

    如果一行代码被修改,那么-号后边一定会跟着+号,且在git log文件中,两行相连

    如果是范围代码修改存在两种情况:

    -比+少,意味着原代码标记-的行都已被修改,多余的+代表新增的行

    -比+多,意味着有的行被修改,多余的-代表的是删除的行,连减时,后边的+需要从连减的初始行与之进行匹配,直到-不够或+不够,多余的代表增加或者减少

上述规则中b的概念比较抽象,我们在这里给大家举例帮助大家理解

eg1:下图中第6-13行(图中的行即--++++++那里)代表的就是,原文件中的第388,389两行被修改了,并在389行下面又新增了4行,这里如果大家有兴趣可以通过git diff去比较,然后手动计算验证一遍

@@ -384,9 +397,14 @@ def executeIII(commitid,branch,moduleid):
                 a = content.encode('unicode-escape').decode('string_escape').encode('utf-8')
                 contentlist = a.split("\n")
                 newlinenum = oldline2newlineNew(contentlist, i)
+                log.info('newlinenumis :%s' % newlinenum)
                 mapcoveragelinelist.append(newlinenum)
-        coverage = ','.join(mapcoveragelinelist)
-        tempdict1['coveragedline']=coverage
+        #异常兼容处理,如果程序正常,一定可以找到提交后对应的行
+        if len(mapcoveragelinelist):
+            coverage = ','.join(mapcoveragelinelist)
+            tempdict1['coveragedline']=coverage
+        else:
+            tempdict1['coveragedline']=[]
         gapdiffresult.append(tempdict1)
         continue

eg2:下图中第6-13行(图中的行即------++那里)代表的就是,原文件中的第402行,403行修改了,并删除了下面的4行,402,403,对应到新文件中即对应第388,389行

@@ -397,14 +384,9 @@ def executeIII(commitid,branch,moduleid):
                 a = content.encode('unicode-escape').decode('string_escape').encode('utf-8')
                 contentlist = a.split("\n")
                 newlinenum = oldline2newlineNew(contentlist, i)
-                log.info('newlinenumis :%s' % newlinenum)
                 mapcoveragelinelist.append(newlinenum)
-        #异常兼容处理,如果程序正常,一定可以找到提交后对应的行
-        if len(mapcoveragelinelist):
-            coverage = ','.join(mapcoveragelinelist)
-            tempdict1['coveragedline']=coverage
-        else:
-            tempdict1['coveragedline']=[]
+        coverage = ','.join(mapcoveragelinelist)
+        tempdict1['coveragedline']=coverage
         gapdiffresult.append(tempdict1)
         continue

是的,你没看错,我只是把两次提交互换了一下,通过这里的学习,我们可以知道如何去判断一个行是否被改动了,或者删除了,或者它的行号发生变化了

到此为止,我们已经了解了增量计算的基本原理,接下来,我将增量计算分为三种模式,分别对应业务测试中的三种情况

1,first:即开发提交后,我们第一次进行测试,我们可以将对应的覆盖率存到数据库中,作为历史覆盖率

2,repeat:即重复测试,是指我们第二次服务部署时,代码没有变动,与上次提交代码一致,此时的覆盖率应该加上上一次的覆盖率,两处覆盖率合并得出总覆盖率

3,gap:即间隔测试,指的是我们第二次服务部署时,代码又有了改动,比如RD修复BUG,我们此时要回归验证,此时的覆盖率应该=本次覆盖率+历史不受影响代码覆盖率

此处,我们不妨通过集合概念来理解

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值