代码覆盖率链路统计

一、前言

在日常开发测试中,代码覆盖率是衡量测试完整性的核心指标。那现有的代码行级别覆盖率工具(如下图)是不行了么,为什么还要做链路覆盖率功能?

代码行级别覆盖率工具

代码行级别覆盖率工具

并非行覆盖率功能不足,而是链路有其独特定位:用于查看接口的调用链路,展示涉及文件的覆盖情况,是流量回放的辅助分析工具。实现效果如下图:

链路覆盖率工具

链路覆盖率工具

回顾产品对此功能的前端设计,需求可概括为:

  1. 能清晰展示函数的调用关系

  2. 要一眼看清覆盖效果,点击能查看具体信息

  3. 当然功能越多越好!

  4. 其他看着发挥吧~

既然产品要求灵活发挥,那就该着手行动了。

但,先别急着写代码。

二、先别急着写代码:搞懂真正的需求

起初我想当然地认为:不就是绘制流程图吗?用 Echarts 画几个节点连线就行。

但真正上手才发现,需求远不止 "画几个节点连线" 这么简单:

  • 要呈现整个系统的函数调用网络,而非零散的节点

  • 要能直观体现函数覆盖情况,快速定位目标函数

  • 点击、鼠标悬浮函数节点,展示不同的覆盖信息

这三个需求翻译过来就是:

  • 如何处理大规模数据(性能问题)

  • 如何让节点自动整齐排列(布局问题)

  • 如何让用户顺畅操作图表(交互问题)

带着这三个问题,开始踩坑之旅。

三、 第一次尝试:用 Echarts 画,结果 "翻车" 了

首先尝试了最熟悉的 Echarts。

3.1 树图的尝试

因为接口提供的是列表数据,在根据边数据关系处理成树型结构后,发现函数调用不单单是一对多的关系。

但树图布局仅支持树型结构,无法展示多对多。这个方案还没开始就pass了。

图片

3.2 Graph的尝试

放弃树图后,进而选择了关系图,当我看到 Graph 的示例后,表示这非常符合想要展示的效果:

series: [{ 
  type:'graph',
  layout: 'none'
}]

图片

但有一个问题犯了难,Graph 的数据,需要 x, y 坐标来确定节点展示的位置。那有没有不用坐标数据,就能自动将节点完美排列出来的图形呢。

基于这个想法,又看到了力引导布局。

3.3 力引导布局的尝试

尝试力引导布局后,节点数据不用计算坐标,开发就更加简单了:

series: [{
  type: 'graph',
  layout: 'force', // 力导向布局 
  force: { 
    repulsion: 100 // 节点之间的排斥力 
  }
}]

初期效果还行,几十个节点的时候,能看出谁调用谁。但当数据量加到 500 个节点,问题出现了:

  • 节点堆成一团,根本分不清谁连谁

图片

显然,力引导布局仅适用于小数据量场景。

那么,Echarts Graph 做为待定方案,我又去试了试别的可视化插件,看看有没有更合适的。

四、第二次尝试:换 Ant Design Charts,又栽了

项目是基于 AntD 组件库写的,那 Ant Design Charts 不就是个专门画流程图的工具嘛,其中 FlowGraph 看起来就很专业,还能和项目的 AntD 组件库无缝衔接。

<FlowGraph
  data={data}
  nodeConfig={{...}}
  edgeConfig={{...}}
/>

新方案的效果立竿见影:连线是带箭头的折线,节点样式也好看了。但新问题也很快出现了:

  • 数据量大时,操作的节点更新信息后,数据重新加载,画布会重新渲染,例如打开抽屉弹窗、变更节点颜色的操作,页面响应就出现了明显的卡顿

  • 产品想要小地图和工具栏来进行显式操作,那怎么设计去将这些功能融入图形中

图片

如何只更新选中的节点,不重新渲染整个画布呢,带着这个问题,又做了进一步探索。

直到看到了AntV G6。

五、终选方案:用 AntV G6,终于摸到门道

经历两次选型不理想后,开始着手研究专业的图可视化引擎。当看到了AntV G6,一个写着强分析、高性能、易扩展标语的产品,那就来试试它。

5.1 解决第一个问题:让 1000 个节点跑起来

初始化配置时,特意找了 1000+ 的节点进行测试:

图片

结果令人惊喜,使用单节点的更新方法,操作后页面完全不卡顿!拖拽、缩放等操作也很流畅。

const graph = new G6.Graph({
  container: 'container',
  layout: {
    type: 'antv-dagre',
    rankdir: 'LR',
    ranksep: 100, // 层级间距
    nodesep: 10, // 节点间距
  },
  // 其他配置...
});

5.2 解决第二个问题:让节点自动排得整整齐齐

之前用 Echarts 的力引导布局,节点总是乱飘,容易出现重叠缠绕的问题。G6 的专业布局算法帮了大忙:

  • antv-dagre布局:函数调用链路从左到右排,一目了然

  • 还可以调节点间距:ranksep: 100(层级间距)、nodesep: 10(节点间距)

5.3 解决第三个问题:让交互体验流畅自然

这部分是最花心思的,结合用户使用习惯,实现了几个核心交互:

1)节点高亮

  • 点击函数时,高亮当前节点,弹窗展示行覆盖信息

图片

  • 鼠标悬浮在函数节点上,前后调用路径高亮显示,并显示更详细的函数覆盖信息

图片

// 更新节点状态
graph.updateNodeData([{ id, states: ['selected'] }]);
// 聚焦节点,使节点在屏幕中间
graph.focusElement(id);
// 重绘图表
graph.draw();
// 自定义显示详情面板函数
showDetailPanel(id);

2)颜色编码:用颜色直观区分覆盖状态,让用户可以一眼就知道哪些函数还没被覆盖。定义的颜色规则如下:

图片

const COVERAGE_COLORS = {
selected: '#fadb14',    // 黄色:当前选中的节点
full: '#52c41a',        // 绿色:覆盖率100%的节点
partial: '#1677ff',     // 蓝色:覆盖率大于0%的节点
none: '#f5222d',        // 红色:覆盖率0%的节点
};
const getNodeColor = (status, isSelected, isActive) => {
let baseColor = COVERAGE_COLORS[status];
if (isSelected) baseColor = COVERAGE_COLORS.selected;
// 添加透明度效果,实现鼠标悬浮时颜色高亮
const alpha = isActive ? '' : '80';
return baseColor + alpha;
};

3)展开/收起:当节点拥有过多子数据时,页面布局就会拉伸的过长,影响浏览效率。通过控制节点和边的显示与隐藏状态,用户可以聚焦关注的部分:

图片

const { edges, nodes } = graph.getData();
// 获取所有子孙节点
const nodeList = getDescendants(nodeId);
// 子节点增加显示隐藏状态
nodes.forEach((node) => {
if (nodeList.includes(node.id)) {
    onCollapseNode({ nodeId: node.id, type: 'node' });
  }
});
// 子边增加显示隐藏状态
edges.forEach((node) => {
const endId = node.target;
if (nodeList.includes(endId)) {
    onCollapseNode({ nodeId: node.id, type: 'edge' });
  }
});
const onCollapseNode = ({ type = '', nodeId = '' }) => {
//处理显示隐藏逻辑,将选择节点及其子节点状态取反
};

4)扩展功能:增加拖拽、放大、缩小、刷新、信息提示窗等功能,用户体验直接拉满:

const graph = new G6.Graph({
behaviors: [
    'drag-canvas',
    'zoom-canvas',
    { type: 'hover-activate', degree: 1 },//路径高亮追踪
  ],
plugins: [{
    type: 'minimap',//迷你图
  }, {
    type: 'toolbar',//工具栏
  }, {
    type: 'tooltip',// 提示窗
  }]
});

六、总结

6.1 从试错中提炼的技术实践

从三次技术尝试的过程来看,初期对插件的选型都基于工具的基础特性,缺乏系统性调研,导致在实际开发中暴露了诸多问题,基于这些实践,总结经验如下:

  1. 充分调研:技术选型前需通过多维度调研明确工具边界:

    • 内部调研:梳理团队现有技术栈、成员对工具的熟悉度、历史项目中类似场景的解决方案,避免重复踩坑;

    • 外部调研:查阅工具官方文档、社区 issue、第三方测评,明确工具的适用场景与短板;

    • 直接咨询:向有经验的同学请教实际开发中的坑点,获取一手实践经验,快速缩小选型范围。

  2. 不迷信“万能工具”:不同工具的设计目标存在差异,技术选型的核心是让工具特性与场景需求精准匹配,而非依赖个人熟练度。

  3. 性能优先于功能:对于复杂图场景,性能是用户体验的基石:

    • 需优先通过技术选型确保页面流畅,再逐步叠加交互功能。若前期忽视性能,即使功能完备,也会因卡顿导致工具不可用。

6.2 未来计划

将链路覆盖率和日常代码变更结合起来

  • 每次代码提交时,团队通常会对变更部分进行针对性测试。如果能够将链路覆盖率与这些代码变更进行关联分析,就可以精准识别出受影响的调用路径,计算增加变更链路覆盖的情况,帮助团队更好地评估代码变更的风险。

如果你也在做类似的可视化需求,欢迎相互交流~

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值