暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

基于Super-Jacoco的精准测试实践之路

咻咻ing 2021-12-06
2112

灵魂拷问

  • 这个版本的影响范围到底有多大?
  • 研发改动了代码,为什么不通知测试?
  • 测试用例真的全面覆盖了吗?
  • 测试同学的测试覆盖情况该怎么评估?

什么是精准测试

概念

借助技术手段、通过辅助算法对软件测试过程进行可视化、分析及优化的过程,使得测试过程更加可视化、智能、可信和精准。

目标

测试质量的评估不在完全依靠个人经验和业务熟练度,而是通过精准的数据来判定。在测试资源有限的条件下,将用例精简到更加有针对性,提高测试效率,减少漏测风险。

核心

  • 研发:研发人员可以看到测试执行用例的代码细节,帮助快速定位和修复缺陷。
  • 测试:测试人员可以通过代码修改范围快速确定测试用例,减少测试的盲目性,提升测试覆盖率。

精准测试实践

  1. 无需对开发代码做任何改造,只需在服务启动命令中添加javaagent
    即可。
  2. 依托于Super-Jacoco,基于Jacoco、Git二次开发,收集两个版本间增量代码差异。
  3. 用户执行测试用例,用例执行过程中Jacoco会记录代码覆盖情况。
  4. 生成可视化的HTML覆盖率报告,协助用例覆盖情况精准分析。

整体流程图

详细使用流程

  1. 业务部署

  • 修改env
    下虚拟机参数

    env:
      - name: OTHER_VM_OPTIONS
        value: '-javaagent:/jacoco-agent.jar=includes=*,output=tcpserver,address=0.0.0.0,port=28048

    super-jacoco服务需要通过agent启动的服务中拉取exec文件

    address
    指定为0.0.0.0即可,但是port
    必须为对外暴漏的端口

  • 添加port

    ports:
      - hostPort: 28048
        containerPort: 28048
        protocol: TCP

  • /home/xxx/org.jacoco.agent-0.8.5runtime.jar
    :agent Jar包存放路径

  • address
    : 部署服务器的机器IP

  • port
    : 部署服务器的空闲port,用于精准测试服务来拉取exec文件

  • 注:如果服务启动时已经有Javaagent参数的,可以再配置一个Javaagent参数,但是Jacoco的agent必须在第一位,如下:

    java -javaagent:jacooc.jar -javaagent:agent2.jar -jar service.jar

  1. 物理机部署业务方服务

    在启动业务方服务时,添加javaagent
    启动参数

    java -javaagent:/home/xxx/org.jacoco.agent-0.8.5runtime.jar=includes=*,output=tcpserver,address={address},port={port} -jar service.jar

  2. K8S部署业务方服务

    在基础镜像中已经包含了agent的Jar包,业务方可以直接使用。

    修改deploy相关的yaml文件
    修改Service相关yaml
    ports:
      - name: jacoco--serve
        protocol: TCP
        port: 28048
        targetPort: 28048

  • 启动覆盖率收集

    在用例执行之前,先启动覆盖率收集,获取两个Git Commit点之间的代码差量报告

    Host为Super Jacoco服务启动的ip和port

    Host: http://ip:port
    Path: /cov/triggerEnvCov
    Method: POST application/json
    Body: 
    {
      "uuid""{随机ID}",
      "type"1,
      "gitUrl""ssh://gitUrl/{your project name}",
      "subModule""",
      "baseVersion""commit id",
      "nowVersion""commit id",
      "address""{address}",
      "port""{port}"
    }
    Response:
    {
      "code"200,
      "msg""success",
      "data"null
    }

    参数说明:

    可以把接口配置到PostMan中,调用启动覆盖率收集,之后即可执行测试用例

    • uuid:随机值,全局唯一;可手动输入,getEnvCoverResult接口需要使用
    • gitUrl: 项目仓库地址
    • baseVersion: 基准的Git CommitID
    • nowVersion:新版本的Git CommitID
    • address:步骤1中的address
    • port:步骤1中的port
  • 获取覆盖率报告

    在测试用例执行后,通过接口/cov/getEnvCoverResult
    获取覆盖率报告

    Host: http://ip:port
    Path: /cov/getEnvCoverResult
    Method: GET
    Query:
     uuid: {uuid}
    Response:
    {
      "code"200,
      "msg""success",
      "data": {
        "coverStatus"1,
        "reportUrl""http://ip:port/uuid/index.html",
        "lineCoverage"60.3,
        "branchCoverage"50.62,
        "errMsg""",
        "logFile""http://ip:port/logs/uuid.log"
      }
    }

    参数说明:

    • uuid:步骤2中的uuid
    • reportUrl:HTML报告访问地址
  • 访问reportUrl
    中的地址即可获取覆盖率报告,报告解读:

    上图为某项目的报告截图示例,对报告理解作简单介绍:

    • 绿色:用例执行覆盖到了该代码
    • 黄色:用例执行部分覆盖了该代码的逻辑
    • 红色:该代码逻辑未被覆盖到
    1. 代码标记颜色说明:

    2. 指标含义解释:

    精准测试使用场景

    1. 提测阶段

    版本提测后,通过触发【启动覆盖率收集】步骤2中的操作,通过【步骤3】获取覆盖率报告,可以获得本次迭代版本相比上个版本的代码变更范围,为测试同学制定测试方案和测试范围提供参考。同时可以评估研发的自测程度。

    2. 测试阶段

    测试完成后,通过获取【获取覆盖率报告】步骤3来查看测试覆盖情况,测试同学可以根据代码染色结果来分析本次测试的完成度。同时也可以驱动测试同学加强代码阅读和分析,提升测试深度。

    3. 回归阶段

    通过PostMan测试集合执行回归用例,除了可以查看测试集合的用例执行结果外,还可以通过覆盖率报告进行分析。

    常见问题

    1. Super-Jacoco的git地址是否支持ssh?

      支持,application.properties
      中的gitlab.username
      gitlab.password
      配置为空值时使用默认的SSH值。你也可以修改super-jacoco中com.xiaoju.basetech.util.GitHandler
      的源码来指定SSH配置,示例代码如下:

      private String private_key = "/Users/wang/.ssh/y";
      SshSessionFactory sshSessionFactory = new JschConfigSessionFactory() {
                  @Override
                  protected void configure(OpenSshConfig.Host host, Session session) {
                      session.setConfig("StrictHostKeyChecking""no");
                  }

                  @Override
                  protected JSch createDefaultJSch(FS fs) throws JSchException {
                      JSch sch = super.createDefaultJSch(fs);
                      sch.addIdentity(private_key); //添加私钥文件
                      return sch;
                  }
              };

              Git git = Git.cloneRepository()
                      .setURI(gitUrl)
                      .setTransportConfigCallback(transport -> {
                          SshTransport sshTransport = (SshTransport) transport;
                          sshTransport.setSshSessionFactory(sshSessionFactory);
                      })
                      .setCredentialsProvider(new UsernamePasswordCredentialsProvider(username, password))
                      .setDirectory(new File(codePath))
                      .setBranch(commitId)
                      .call();
              // 切换到指定commitId
              checkoutBranch(git, commitId);
              return git;


    2. 代码安全问题

      super-jacoco是根据源码来做增量代码差异化分析的,如果使用统一账户拉取代码,那这个账号可能就拥有了所有代码的权限,可以分配只读权限。

    3. K8S中可以使用吗?

      上面的步骤中有K8S的使用方式,主要涉及两个问题,1. agent放在哪里?2. pod重启之后可能IP会变掉?

      1. 可以把agent放入到基础镜像或者打包到项目中。2. 把address配置成0.0.0.0之后,请求参数中的address写成K8S集群的访问Ip即可。
    4. 测试人员无法获取到代码Commit ID?

      可能很多公司的测试其实是没有代码仓库权限的,只是对迭代的版本有直观的认知。这个就需要依赖公司内部的协调处理了。

    5. 覆盖率需要达到100%吗?

      代码覆盖率其实很难达到100%,代码中可能会有一些catch的异常或者lombok生成的代码用例很难覆盖到。而且覆盖率也很难说达到一个稳定的值来作为公司内部测试完成的度量。

    结语

    借助于super-jacoco,我们可以获取用例执行的覆盖率情况,生成覆盖率报告来协助我们分析用例是否完善。但这才是精准测试迈出的第一步,这个覆盖率报告如何解读,如何作用于研发流程还需要不断实践来总结经验。

    未来,还要继续探索如何根据覆盖率来推导代码变动影响的接口范围、分析冗余用例提升回归效率、根据代码变动自定推荐用例等等。

    欢迎有兴趣的朋友一起关注交流


    文章转载自咻咻ing,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

    评论