转转QA CodeDiff 实现方案简述

笑哼 for 转转QA · 2018年11月01日 · 最后由 ada721 回复于 2020年05月07日 · 4267 次阅读

作者 | 黄莹

前言

CodeDiff-从字面上理解就是代码差异的比较,其实我们的测试工作从某种程度上可以理解为针对代码逻辑的测试。因此 CodeDiff 可以作为一种补充测试的手段,辅助我们在测试过程中通过代码内容更好地判断测试范围,以及加深对技术实现的理解,使得我们能够从内到外更好地把控项目的风险与质量。

CodeDiff 的意义

在日常工作中大家进行 CodeDiff 所用的工具和方式多样化,但其目的都是通过两个版本的比对拿到差异内容,通过差异内容进行流程性或者模块化的梳理从而得出此次提测的改动点,然后再对其进行需求/业务相关性评估。CodeDiff 需要测试人员熟悉原有业务流程与新需求所涉及的范围,对所涉及模块之间上下游的调用关系、数据流向、状态变化等有一定程度的了解,通过了解开发设计方案、接口改动等等方面来综合评估影响面以及测试/回归范围。

为什么要自研?

1、CodeDiff 工具方式多样化,希望提供一个统一、简易的平台(支持 SVN/Git 两种模式、省去打开 IDE、反复拉代码、查看无权限等繁琐操作),让每个人能快速进行 Diff,培养同学 diff 代码的习惯;
2、目前公司开发模式统一切成 Git,相比 Git 平台提供的能力,我们希望实现任意两个 CommitId/分支之间进行 diff 的方式(两种 Diff 模式的优缺点);
3、参考业界其他互联网公司自研案例,自研的方案拓展性更强,且方便接入公司项目管理流程之中,使其能够平台化、提升效能;
CodeDiff 接入到 beetle 中,与每一次编译做结合,开发人员可以增量查看每次编译的 diff 结果,测试人员可以看到每次提测基于首次编译的增量 diff,也支持自主选择版本。
4、可以为所有基于代码差异的测试方法所使用,如 CodeReview、代码覆盖率统计、代码静态检测、语法检测等。

设计实现

1、基本思路
自研的 CodeDiff 平台支持 SVN、Git 两种模式,虽然这两种版本控制系统存在诸多不同(集中式/分布式、用法思想上等),但 CodeDiff 实现的基本思路是一致的:基于任意两个版本/分支进行代码比对,得出差异结果,再将差异结果进行解析并进行展现。

2、实现方案
SVN-SVNKit
纯 Java 的 SVN 版本连接库,整个连接底层由 Java 实现。一共提供两个层次的 API,通过这两个 API 就可以基本实现与客户端相同效果的操作,不需要额外的支持:

  • Low-Level API:针对 Subversion Repository 的操作,相当于操作 Repository 的中间驱动,实现了对底层协议与 Subversion 仓库的对话,比较抽象,可以理解为一个包含版本控制的、抽象复杂的树结构。
  • High-Level API:针对 Working Copy 的一系列操作,将所有管理工作拷贝的操作逻辑分配在不同的 SVN*Client 中。不同的操作基于不同的 SVN*Client 去实现。例如:所有的工作拷贝的更新操作如 checkout、update 都有 SVNUpdateClient 这个类去执行。操作方法和参数与 SVN 客户端命令行相似,其底层实现实际上也调用了 Low-Level API。

GIT-JGIT
纯 Java 的 Git 版本控制,提供了 Git 命令的 Java API,通过调用 API 可实现创建本地仓库、远程操作代码库如 clone、fetch、push、diff 等命令,可以达到与客户端相同的操作效果。
举个栗子:将某个 git 工程的版本库 clone 到本地,git 命令行:$ git clone [url]

目前转转的研发模式已经切换至 Git,接下来就以 Git 为例来展开介绍基于 Git 的 CodeDiff 具体是如何实现的:

Part1-差异内容的获取

(1)JGit Authentication:JGit 验证机制大部分与本地 Git 相同,支持 SSH 协议和 HTTP(S) 协议,可以通过调用 JGit 提供的验证 API 来安全地连接远程 Git 库;
(2)通过实例化需要用到的 git 命令的方法来实现对本地仓库的操作。如 CloneCommand,FetchCommand,CheckoutCommand 等等,这些命令都有一个相同的基本类-TransportCommand,它提供了我们所实例的所有方法;
(3)拿到需要进行对比的两个版本参数后,通过调用 git.diff() 方法拿到基于这两个版本的差异结果,将结果交由处理器进行逐行解析最后返回;

Part2-全文件内容拼接

(4)拿到差异内容后,根据文件名在本地代码仓库查找目标文件,找到之后通过处理器对目标文件的内容进行逐行解析;
(5)根据文件修改类型(modify/add/remove)决定全文件内容的拼接策略,最后得到目标文件的完整内容后返回。

写在最后

1、 CodeDiff 整体方案的设计和实现经历了一版又一版的迭代优化,与 beetle 平台集成之后也更好地服务了技术同学的日常工作,真正实现不用拉代码一键 diff 的目的,希望 CodeDiff 可以真正融入我们测试工作的日常,成为辅助测试、把控风险的有效手段,让我们每一次发布上线变得更为可靠。
2、CodeDiff 为代码覆盖率统计、CodeReview 的实现提供了能力支撑,也实现了相应的拓展,同时还适用于所有基于代码差异的测试方法如代码静态检测、语法检测等,为测试方法的多样化探索过程提供了更多可能性。

共收到 11 条回复 时间 点赞

这种方案是不是不能排除注释和空行这种非逻辑变更?

jacoco 不就是现成的吗?

还有一个现实意义就是代码分支合并的时候 QA 做对应确认
确认没有把非本次版本的内容误合并进来导致漏测

AngryTester 回复

排除注释和空行的情况可目前是支持的,但需要根据实际应用场景来决定是否需要排除。如:基于 codediff 的代码覆盖率统计就是排除了注解、空行、import 等无实际意义的变更。目前 codediff 已经支持相应能力的拓展。

hellomike 回复

jacoco 是基于代码差异去统计覆盖率的测试方法,本文探讨的是代码差异的实现方案,这个实现方案可以适用于所有基于代码差异的测试方法,包括覆盖率。

6楼 已删除
纯稀饭 回复

说的很对,是 codediff 意义的一个补充,赞

有没有开源

OBJ 回复

暂时没咧,哈哈

准备开源不哦

期待开源

go 语言的也可以吗?

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册