测试左移 - 快速玩转 Debug
背 景
一段代码的问题产生阶段可以分为:编译期和运行时
编译期的代码可以由工具(idea、eclipse)在程序编码过程中提示错误,解决了语法上的标准问题
运行时的代码在程序启动、运行过程中出现程序异常、逻辑异常的错误
当程序发生异常: 如返回结果不对、 没响应、抛异常、肉眼又发现不了的错误!通常这种情况我们就需要调试代码
学习的意义
QA 同学通过学习 debug,能够追踪代码的运行过程,快速熟悉代码实现和调用链路,扩展 case 的设计思路,同时从黑盒转向白盒,提高问题定位、精准 case 设计的能力。
玩 转 Debug
一、基本介绍
Debug 视图
常用按钮
断点分类(常用断点)
1、行断点
最常用的断点方式,一般用于某个方法内部逻辑能预估的位置进行断点,可以忽略上文过程中的链路
2、方法断点
方法断点可直接作用在方法上面,如果不确定是哪个方法,可以直接断点到接口上,会自动找到对应的实现,要注意的是,接口上断点的标记是一个菱形
3、属性断点
是打在属性上的,我们无需再 getter setter 方法上打断点,在属性上打上断点,就会出现一个小眼睛的标志
小眼睛右键可进行设置断点的触发类型:修改和访问
日常开发或者定位赋值问题的时候,可以通过这个属性断点方式来排查
4、流断点
在使用 lambda 或者流操作时候,想要看见过程中做了些什么,可以通过流断点的方法,查看
这个按钮即可展示视图,在每个过程中做了什么动作
二、断点设置
1、首先,我们找到需要断点的代码,根据上面断点分类,选择不同的断点类型,我们采用行断点,点击某行,进行断点标记
2、对于本地单元测试,我们可以直接点击绿色的三角箭头->选择 debug 运行模式
对于远程调试,我们可以选择 idea 右上角的小虫子,启动调试即可,和点击绿色三角箭头中的 Debug Run 效果一致
远程调试需要注意的要点:
本地的代码必须和远程服务器运行的代码保持一致
远程调试不要在生产环境进行,否则在断点未关闭的情况下,会造成服务阻塞,严重的造成线上问题
三、启动调试
我们以一个案例来演示学习 Debug 的意义
求 1-10 阶乘之和
1!+2!+3!+......+10! = 4037913
以下代码
在编译期:代码没有任何异常,但是运行结果和我们预期是不一致的,在没有日志的情况下,我们无法通过肉眼直接判断问题出在哪里,此时 debug 调试的作用就显现出来了
阶乘调试
1、首先,标记断点,启动调试
可以在变量区很清楚的看见目前变量的结果
2、使用【
】按钮进行一步步执行
可以发现 i=1 的情况下,阶乘之和 sum 变量值是正确的,继续执行
3、继续【
】调试,i=2 的情况下,阶乘之和=3,结果也是正确的,继续执行
4、此时 i=3 执行,发现 sum 的值居然变成了 15,正常的 1!+2!+3!的阶乘之和应该是 6 此处就可以发现计算有问题,那么问题在哪呢,使用【
】重新运行加载
观察 i=3 的情况下变量的变化
5、i=3 的情况下,从图中可以看出 S=2,计算 2*1=2,J++再计算就是 2*2=4,这里实际上就可以看出来问题,3 的阶乘应该是 1*2*3=6
而此处运算完结果是(2*1)+(2*2)+(2*3)=12,SUM=3,12+3=15
发现问题所在,long s =1 ,只在 for 循环外面定义了初始化的变量,每次都会累加而没有重置,每次计算 s 都是用累加的值进行计算,所以会出问题
6、知晓问题结果后,我们修改代码,增加 s 在循环体中的重置,重新 debug 运行
在 i=3 的时候,可以发现 s 变量的结果符合预期
7、释放代码,查看最终结果,和我们的预期值一致
此处也能够看出来 debug 调试在整个过程中排查问题、定位问题起到了关键的作用
四、调试技巧
高效 debug
1、断点-【条件判断】
在代码中,经常会遇见 for 循环,但是循环集合可能会很大,一步步的调试到我们想要的那个下标值,执行起来非常麻烦,那么这个时候就可以运用条件判断进行断点
例如在阶乘运算中,我不想一步步的执行很多遍才进入有问题的 i==3,那么我可以在 for 循环的循环体中进行断点,通过右键断点,设置 i 的条件,在满足条件时,才停在断点处,否则直接运行。如下
从图中可以很明显看出来直接 debug 的时候,i 执行到了第三次后,才进行断点拦截,前面的都会直接执行不拦截,并且断点标记多了一个?号标记
2、断点-【表达式计算】
个人认为是 idea 调试里面最好用的功能,计算表达式有两个作用,都是在运行时作用
查看表达式的值
设置表达式的值
设置表达式的值
当前 debug 下,list=0,所以这个输出永远不会打印
使用表达式计算,执行 list.add 后,返回结果是 true,同时能看见 size 长度变更为 1
这个时候再次向下执行,即可进入 for 循环的循环体中进行打印
查看表达式的值
在一些复杂逻辑中,编码者会将多行代码调整为一行,提高了简洁性,但是降低了可读性,这个时候就可以使用表达式,将计算拆分出来一个个查看,可以更好的理解这一行代码表达的意思和计算的逻辑
定 位 问 题
1、在程序运行日志中,有 log 抛出异常,通常你可以不需要任何思考,将错误拷贝后在代码中搜索,如有多个同样的,可以根据参数和日志打印内容进行筛选
2、没有日志情况下怎么办,不知道入口处,那就只能通过抓包等手段获取请求的接口,然后在 idea 中查找对应的接口,在实现类的入口处进行断点;对代码有一定的阅读能力的测试,可以进行简单走读判断代码主体逻辑再进行断点标记,缩小范围
3、 在无法判断异常位置,并且代码逻辑又多的情况下,我们还可以通过多行断点标记的方式,直接配合
按钮,运行会直接跳入下一个断点中,上一个断点到下一个断点中间的代码都不会步入,如下
通过该方式,可以进行代码分块的情况下快速定位问题点
总 结
Debug 能力是定位问题的一个手段,能够给 QA 同学带来更多的实践经验
提高我们对业务逻辑和数据交互流程有更清晰的认知
了解基本原理和使用,拓宽设计 case 的思路
将代码学习融入到日常工作中,理论结合实践,能够快速提高自己的代码能力
作者:艾超
> 转转研发中心及业界小伙伴们的技术学习交流平台,定期分享一线的实战经验及业界前沿的技术话题。
> 关注公众号「转转技术」(综合性)、「大转转 FE」(专注于 FE)、「转转 QA」(专注于 QA),更多干货实践,欢迎交流分享~
版权声明: 本文为 InfoQ 作者【转转技术团队】的原创文章。
原文链接:【http://xie.infoq.cn/article/28faa787733aa3316f12938ff】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论