白盒测试 IDEA 远程调试 Java 代码实践及心得分享

小敏 · 2017年07月11日 · 最后由 许伟栋 回复于 2017年07月14日 · 2934 次阅读
本帖已被设为精华帖!

刚工作那会,每听人讲起通过远程调试代码来定位 bug 都觉得很高端,后来在工作中不断尝试,到现在远程调试代码已成为自己的一种常用辅助测试手段,不仅减少与开发的沟通成本,在提升测试效率的同时,也增加了对代码的理解程度,提升了测试的深度,不可不说优点多多。

下面简单介绍下使用 Intellij IDEA 进行远程调试需要进行的配置及服务端的相关配置,并用一个实例简单介绍下远程调试的一般过程,最后分析下我认为的 QA 进行远程代码调试的一些优缺点。

一、本机 Intellij IDEA 远程调试配置

1、打开 Inteliij IDEA,顶部菜单栏选择 Run-> Edit Configurations,进入下图的 Run/Debug Configurations 界面。
2、点击左上角'+'号,选择 Remote。(注意不是 tomcat server->remote,之前在某篇教程上看到是这个,怎么弄都不对。)
分别填写右侧三个红框中的参数:Name,Host(运行代码的服务端 ip),Port(想要指定的远程调试端口)。
3、点击界面右下角 Apply 按钮即可。
avatar

二、服务端增加指定 JVM 启动参数,以支持远程调试

在 Tomcat 启动脚本 TOMCAT_HOME/bin/catalina.sh 的首行或 CATALINA_OPTS 字段说明行后添加 CATALINA_OPTS 参数配置,参数值复制上图中间红框中的内容即可:

CATALINA_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=28000"

配置添加之后,重启 tomcat 即可生效。

三、使用远程调试定位代码问题实例

完成一二两步就可以开始远程调试了,下面以一个实例,来说明一下远程调试的一般过程。

1、发现问题

之前一次新功能测试中,需求是在续费的第二个页面增加一条显示信息,在续费的第一个页面填写相关信息点击下一步按钮时,本应该直接进入下一页,但实际跳转到 ERROR 页,查看 url 发现相关接口返回了自定义返回码 500,提示服务器错误。

2、查看日志,定位问题代码位置

通过查看业务日志,发现是在 PaymentRestServiceImpl.java 中的 448 行的 availableRenewMonths 方法中抛了 NPE(java.lang.NullPointerException)。
avatar

3、查看问题代码前后的业务逻辑

通过代码走读可以看出,这个方法用于获取可选的续费时间段,对 systemSettingService.defaultRenewDurations() 进行遍历时抛了 NPE。
avatar

4、打断点,进行远程调试

在 PaymentRestServiceImpl.java 的 448 行打上断点 (断点位置可视具体情况而定)。
在 Intellij IDEA 顶部菜单栏选择 Run-> Debug 'Remote 界面中指定的 Name';或者在下图中间红框中选择对应 Name 后点击右侧的绿色图标,在下方的 Console 区出现如下提示语则表示已成功连上远程服务器。
注意:本地代码分支及版本号要与远程服务端的代码一致。
avatar
重新在续费页面输入信息点击下一步按钮时,调试程序会停留在断点处,即为下图左侧的勾号所在位置。IDEA 界面下方会出现 Debug 视图,左下角 Frames 区是方法调用堆栈区,第一行显示当前程序停留的代码行,中间 Variables 区显示变量信息,右下角 Watches 区可添加观测变量。
中间红框中为 5 个常用的调试按钮,从左到右分别为:
1、step over:执行下一行,有方法调用则执行后返回,到下一行
2、step into:执行下一行,有自定义方法则进入其中(不会进入官方类库的方法)
3、force step into:执行下一行,任何方法都能进入
4、step out:跳出当前方法返回被调用处的下一行
5、drop frame:返回当前方法的调用处,即 Frames 区的下一行显示的代码处
avatar
在右下角 Watches 中添加观测变量 systemSettingService.defaultRenewDurations(),值为 NPE。点击 step into 按钮进入该方法中,可以看出,该方法要返回续费时的可选时间段 getRenewDurations,但代码逻辑却以购买的可选时间段 getPurchaseDurations 非空作为判断条件,但为什么抛 NPE 呢?查询 redis 中对应的配置项信息,发现配置项中只有购买的可选时间段,没有续费的可选时间段,所以正好符合代码中的非空判断,所以返回了 NPE。到这里就可以确定问题代码的根源了。
avatar

5、问题刨根问底及后续改进

作为一名负责任的 QA,到这里问题还没结束,还需要对问题进行进一步的分析。
续费功能之前一直在用,为啥突然出问题呢?想起之前产品提需求,要修改购买时的可选时间段,应该是跟这个有关系。然后在 jira 上提 bug 给开发修复,描述下现象,再贴上如上截图,问题就一目了然了。然后询问下开发,导致问题的根本原因,是因为之前续费和购买获取可选时间段的方法是公用的,后来购买逻辑变更,续费重写方法,但复用之前代码时 getPurchaseDurations 方法没有全改掉,导致前后逻辑不一样。

但我在 git 上查看提交购买可选时间段功能的代码版本,并没有看到上述问题代码的修改。初步猜测可能是开发没有按照规范提交代码,一个功能点分多个版本来提交了。然后跟开发确认了一下这个猜想,发现确实是把问题代码的修改提交在另一个功能点的代码版本中了。针对这个问题跟开发商量了一下,以后一个功能点的修改在 git 上只提交一次,这样方便查看代码变更。

业务逻辑的变更,特别是代码重构时,往往会出现类似上面的修改功能 A 导致功能 B 异常的一些问题。这种情况比较好的测试方法是进行变更代码走读,然后设计与代码变更相关的回归用例,保证测试用例的有效性。

上面讲的例子比较简单,但也比较典型。在业务很复杂时,问题定位时可能需要开发的一些帮助。若对代码很不熟或业务逻辑实在太复杂时,考虑时间成本,可以直接让开发进行远程调试,自己搬个凳子坐旁边看他如何操作,遇到不懂的地方就要借机多问一些问题,能学一点是一点,看几次慢慢就会上手了。

四、QA 进行远程代码调试的一些优缺点

以上文例子来说,若 QA 同学不进行远程调试,而是直接反馈开发,续费的时候接口返回 500,一般会发生如下几个来回的交流:
1、开发根据 QA 描述的现象,自己在页面操作以重现问题
2、看日志,并通过远程调试进行问题定位,然后反馈 QA 问题所在
3、QA 针对开发的描述理解问题所在,并设计回归用例(对代码不熟的话的时候听开发的问题描述常常是模棱两可)
4、开发代码修复并重新部署后,QA 进行回归测试
若 QA 同学自己能进行代码远程调试来定位问题,步骤 1 可省略,步骤 3 前半部可省略,且设计回归用例更具有针对性,步骤 2 的执行者从开发变成 QA。

下面罗列下个人理解的 QA 进行代码远程调试的优缺点:
缺点:
1、测试时间开销长,在测试任务很紧时不适用
2、有一定门槛,需要 QA 对代码有一定的理解
优点:
1、节省双方的沟通成本
2、锻炼 QA 同学独立排查问题的能力
3、增加对代码的理解程度,提升测试的深度
4、增加开发对 QA 同学的认可度,以后沟通合作起来更方面
5、提升 QA 自身的成就感

关于缺点 1,我认为要做一个有追求的 QA,进行基本的代码走读和分析能力是必备的技能之一。只满足于表面的功能测试不利于以后的发展。

关于优点 4,想特别说明一下。我记得每每反馈开发代码哪行哪行写错了,应该如何改,特别是在发现一些复杂业务逻辑的问题时,开发同学都会赞叹 QA 同学很厉害。开发对 QA 同学的工作会越来越认可,在写代码时也会更谨慎一些,毕竟对开发来说,被 QA 指出哪里哪里写错了肯定多少会有些尴尬的。但是在跟开发沟通的时候要注意使用比较友好的口气,千万别用指责的口气,这样肯定会恶化双方的关系,不利于后续的合作。在测试过程中肯定会有需要开发配合的地方,跟开发保持良好的关系,开发也会乐意帮忙。

综合来讲,在测试时间不是很紧时,遇到问题时 QA 直接进行远程调试去排查问题还是很适用的。而且随着对项目代码的理解程度的加深,定位问题的速度会越来越快。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 7 条回复 时间 点赞
小敏 [该话题已被删除] 中提及了此贴 12月20日 16:43
小敏 2017,在跌跌撞撞中成长和蜕变 中提及了此贴 12月28日 16:25
小敏 [该话题已被删除] 中提及了此贴 12月27日 19:03
小敏 [该话题已被删除] 中提及了此贴 12月28日 15:17

请问下什么场景需要远程调试,本地直接拉取对应分支代码直接调试不是也可以么?

南风 回复

如果出现的问题只在特定环境出现时必须用远程调试(如某问题在测试环境必现,但在开发环境 ok),一般情况下在本地直接调试也是可以的,但还需要本地起 tomcat 服务,相对来说会比较麻烦一些。

南风 回复

如果整套环境有非常多的后端依赖服务,不仅仅是一个 webserver 那么简单,尤其针对分布式的环境,不太可能在本地就能搭建起一整套环境。并且出现问题的环境的数据库跟本地的数据库也是不一样的。如果能直接在远程进行调试,是一种不错的选择。

Nisir 回复

倪子分析得透彻!

思寒_seveniruby 将本帖设为了精华贴 07月13日 19:58
许伟栋 回复

不同项目情况不同吧,我之前负责的项目人比较少,一般远程 debug 之前在群里跟其他同事说一声就好,同时需要使用环境的情况比较少

小敏 回复

确实是视项目而定😅

远程调试可以很大程度上节省本地环境搭建的成本,但是一般远程的属于公共资源,如果我们 debug 访问的话会导致他人无法访问,所以个人觉得还是本地调试 + 日志分析比较稳妥(除去两位所说的特定或复杂场景)

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