测试之道:定位问题的技术
前言
作为测试来说,每天最多打交道的就是bug,但其实我们在工作中会发现有些测试人员是不知道如何定位bug的,所以在提bug的时候只是描述了一些表面的现象,其实这种bug严格来说并不是一个合格的bug。可能有人会问,为什么这篇文章不叫“定位bug的技术”而是“定位问题的技术”呢?那是因为在我们测试工作过程中,我们遇到的问题很多并不是bug,作为一个专业的测试,我们一定要学会分析和辨别,才能提出一个合格有效的bug。
第一章 定位问题的思路
1-1. 学会定位问题之前,我们需要先了解什么?
了解产品,了解开发
第一个问题:我们拿到的每个需求都是可以实现的吗?
答案当然是不一定,这里说的不一定,既包括技术暂时无法实现的不一定,也包括产品需求本身有问题,比如:同样的需求目标,其他方式做起来更符合现在的代码框架,节省人力成本且能快速上线,或者需求本身和已有逻辑相悖等
第二个问题:我们每拿到一个需求,其实作为测试来说,脑中应该已经要了解这个需求大致应该如何实现了,但是我们想的实现方案就是开发会用的方案么?
答案当然也是不一定!
而且每个需求都有可能不止有一种实现方案,开发选择一种方案,就有可能有这种方案的优缺点,那哪些缺点是可以接受的,哪些是不可以接受的,测试作为把关者一定要清楚,如果觉得开发选择的实现方案和需求有出入应该及时提出
上面讲的是从实现方案考虑,可能大家会纳闷,定位问题为什么要讲实现方案,其实提bug并不是从提测后才开始,需求评审开始的时候就已经开始产生bug了,需求逻辑的漏洞,开发实现方案的选择会带来的问题这些都是测试关注的范围
了解技术实现的本质
关于这一点,每个人感受应该都不完全一样,这里我想讲以下自己的看法,每个需求到最终实现,基本都对应着一个处理,前端也好,后端也好,总有人要去做,所以我们最终测试的样式,功能,数据,交互,逻辑等等都是来自每一行代码的设计。我们不会看到一个文案,一个UI,一个toast,一个接口的返回是无缘无故出现在我们的产品中的
1-2. 定位问题的步骤
关于定位问题的步骤我想说有两种思路
第一种是我自己总结了一下,大概分为以下四个步骤:
What is it:这是个什么问题?
Where is it from:问题来源哪里(APP,网站或其他产品形态)?
Which point does it belong to:这个问题属于哪个端?
How to deal with it:如何处理这个问题?
这个步骤并不一定适用于所有的问题,但是大多数我们常见的bug应该都可以通过这个步骤来进行分析和定位
第二种是我参加公司培训《拆解问题的技术》中学到的,就是:5 why分析法。关于什么是5 why分析法,我们直接上百度:https://baike.baidu.com/item/5why%E5%88%86%E6%9E%90%E6%B3%95/575907?fr=aladdin
具体讲一下5 why分析法应该怎么用,这里借用下老师的ppt
5 Why分析法不仅仅是问5次,只要能通过连续追问找到最核心的问题就可以
第二章 如何定位前端问题
2-1. UI问题:
一般对于UI问题的定位是最简单的,但是UI展示中有些元素是需要前端代码写死的,有些是动态获取的,还有一些是后端返回的,每种不同的实现方式都对应着不同的问题。
先说前端代码写死的类型,这种可能写死的是文案,图片,视频,动画等等,我们在发现UI和需求不一致的时候,就要考虑这个地方是前端代码写死的文案并渲染出的样式呢?还是设计给的图片,直接写死的图片呢?动态获取也包括很多种不同的类型,比如某个图片或者模块只有在用户进行某些操作时才会展示。
接下来我们以网易kms系统(https://kms.netease.com/home)为例直接看区别
第一个例子:比如我们发现这个网站首页的发布按钮文案或者样式和UI不一致,我们应该如何定位呢?
如下图所示,直接通过F12打开控制台(这里以chrome浏览器为例),在elements中我们定位到发布这个按钮上,会发现发布文案和图标都是前端写死的,此时如果不一致,就说明前端html中文案或者css样式有问题,这就是一个前端的bug
如果此时是网站左上角的“网易KM”文案或者样式显示不对呢?我们用第一个例子中同样的方式查看前端页面元素,此时我们发现这个网易KM本身是一个图片,此时若显示不对,则需要设计重新出图,提供给开发替换。
而如果图片显示并没有问题,只是位置不对(比如这个logo我们要展示在底部或者靠右展示),那就需要前端开发来调整位置了
通过上面这个非常简单的例子,我们能看到,一个看似明显的问题其实也是对应不同的处理方式的
2-2. 页面元素操作问题:
我们在页面上进行浏览,点击等操作时,每个操作对应的响应和我们的预期不一致时,我们如何去定位呢?下面我们还是通过几个例子来进行分析
第一个例子:我们分别点击导航栏中的职业库和易-learning,会发现这两个导航都会进行跳转,但是跳转方式却不一样。
我们还是通过控制台来查看,会发现这两个都是a标签,区别就是:1. 内部地址和其他网站地址;2. 易-learing中设置了target="_blank",加了这个在点击这个a标签的时候就会从新的页面打开,相信有了解过前端的同学都理解。
针对其他前端操作也都有不同的处理,其实一般来说,页面操作的处理操作一般都是由前端来做的,每种不同的处理可能都对应着不同的交互体验
2-3. 数据处理:
前端在数据处理方面也包括很多方面,在这里暂时主要讲两种,数据传参和数据渲染
第一个例子:比如此时职业库中的职业分类顺序或者文案错误了,这个时候应该提给前端还是后端呢
我们通过刚刚的方式定位,F12查看元素发现前端标签中有技术和测试文案,那是不是说明这个问题就属于前端bug呢?其实不是的,我们通过抓包请求会发现profession_articles_rank这个接口本身返回的数据就是整个职业分类的数据框架,所以这个问题就应该属于后端
我们再来看第二个例子:我们在职业库分类中点击技术下的二级分类“测试”发现展示的是“服务端”分类下的数据,对于这个问题该如何定位呢?
我知道很多人会说这肯定是后端问题,这不是后端返回数据不对么?其实不一定
继续上抓包,我们分别点击服务端和测试两个二级分类,会发现进行了两次view_profession接口的调用,这两次调用很明显看到的区别就是:传参profession_id不一样,不得不说这个命名也是很规范,通过命名大概就知道这就是分类id,等于前端传参对应id给后端,后端返回对应数据,如果此时测试id应该是7而点击二级分类“测试”时调用接口传参却为2,那这就妥妥的是一个前端传参bug。如果此时前端传参并没有问题,返回数据有问题,那我们就要分析接口了,这个在后面再讲
第三章 如何定位移动端问题
其实移动端问题和前端问题定位思路是类似的,只不过移动端有它的一些特性,如果说web端是基于浏览器的,客户端就是基于手机系统的,系统有不同就注定了会面临不同的问题和不同的解决方案
3-1. 原生典型问题:
1. 开屏广告:一般开屏广告包括图片,跳转,频率,停留时间等;那如果测试过程中我们发现开屏广告相关的bug该如何定位呢
第一个例子:开屏广告配置了弹不出来?
一般开屏广告都是在应用启动时要展示的,但是开屏广告数据一般又都是通过后端接口返回的,所以一般启动app后我们需要保证app能拿到开屏广告数据,在下一次启动app的时候生效,了解了这个对于开屏广告为什么弹不出我们就可以这样思考?
为什么开屏广告配置了弹不出来?→因为APP端没有拿到广告数据→为什么没有拿到广告数据?→APP根本就没调用接口→结论:APP端忘记调用接口
为什么开屏广告配置了弹不出来?→因为APP是第一次启动还没拿到→结论:正常
为什么开屏广告配置了弹不出来?→因为接口没有返回→为什么接口没有返回→因为广告没有上线被过滤了→结论就是测试操作问题
2. 页面显示
第二个例子:购买了课程学习页面没显示?
为什么没显示→因为接口报错了→接口报什么错了→空指针了→为什么空指针了→数据库有脏数据→结论:清理脏数据
3. 系统权限:APP内打开摄像头后显示黑屏?
通过上面的流程,我们来分析可能会造成这个问题的原因会有哪些?
3-2. 与H5交互问题:
本质上说这两者之间就是两种调用:APP 调用 H5 的代码或者H5 调用 APP 的代码,那对于测试来说原生页面和H5页面有什么不同?
端的适配,数据传输,不同网络下的页面加载及渲染效果,屏幕操作,系统干预(锁屏,断网等),显示适配,翻页加载等等
|
原生页面
|
H5页面
|
|
|
优势
|
依托操作系统,交互性最强,性能最好。
1)运行速度比较快
2)使用设备的底层功能,如摄像头、方向、重力传感器、拨号、GPS、语音、短信、蓝牙等
3)在界面设计、功能模块、操作逻辑等层面相较web更易做到App的便捷性和舒适性,功能更加强大
4)节省流量
|
1)运行在浏览器上,只需要开发一次便可以在不同的操作系统上显示
2)迭代版本,不需要打包便可以发布(实时更新、快速迭代),与云端实现实时数据交互
3)开发成本低,浏览器适配简单,发布门槛较低
4)无需下载,打开网址就能访问。
|
|
劣势
|
1)不同的操作系统(android 和ios)需要独立的进行开发,使用各自的开发包、开发工具和控件
2)每次有更新,都需要重新打包发布到平台,向各个商店进行提交审核。
3)开发成本比较高
|
1)每次打开,都得重新加载获取数据
2)过于依赖网络,速度无法保证,在弱网环境下,不但耗费流量,且加载缓慢。
3)只能使用有限的底层功能
4)仍处于发展阶段,部分功能无法在基于现有技术的浏览器基础上实现。
|
看一个例子:APP内H5页面显示空白问题
我们这次通过我之前自己总结的四个步骤(3WH)进行分析
What:这是个什么页面?(页面地址是什么?抓包)
Where:这个页面哪来的?(后端返回?客户端写死?参数谁拼的?)
Which:这个页面基于哪个端进行访问?(iOS?Android?)
How:如何解决打不开的问题?(参数拼错了?接口报错了?地址错了?网络问题?APP未授权网络权限?等等)
3-3. 与其他APP交互问题:
常见的与其他APP的交互,比如:调起微信,支付宝,QQ等,看下两端分别调用其他应用的实现方案:
|
Android
|
iOS
|
|
|
方式
|
显式调用跳转
隐式调用跳转
|
原则上iOS的沙箱原理,是阻止一个app去访问其他app的资源乃至是系统底层的资源的
但是我们可以通过一种变相的方式:通过对应的URL模式和其他程序进行通讯
|
|
流程
|
参照:https://www.jianshu.com/p/f36f788b65d8
|
注册定制的URL模式→处理URL请求→app中调用
|
通过了解调用的方式,我们更容易定位每一个问题出在哪里
第四章 如何定位后端问题
4-1. 了解HTTP状态码
首先我们先看下HTTP状态码分别对应关系,遇到如下响应状态码问题就去一一对应,比如:400 Bad Request:检查请求发起方发起的请求是否有误;404 Not Found:一般是接口找不到了,要么路径错误,要么对应服务上没有部署相关的后端代码;502 Bad Gateway:服务器问题,检查服务是否正常启动
|
状态码
|
状态码英文名称
|
中文描述
|
|
100
|
Continue
|
继续。
客户端
应继续其请求
|
|
101
|
Switching Protocols
|
切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议
|
|
200
|
OK
|
请求成功。一般用于GET与POST请求
|
|
201
|
Created
|
已创建。成功请求并创建了新的资源
|
|
202
|
Accepted
|
已接受。已经接受请求,但未处理完成
|
|
203
|
Non-Authoritative Information
|
非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本
|
|
204
|
No Content
|
无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
|
|
205
|
Reset Content
|
重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域
|
|
206
|
Partial Content
|
部分内容。服务器成功处理了部分GET请求
|
|
300
|
Multiple Choices
|
多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择
|
|
301
|
Moved Permanently
|
永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
|
|
302
|
Found
|
临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
|
|
303
|
See Other
|
查看其它地址。与301类似。使用GET和POST请求查看
|
|
304
|
Not Modified
|
未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
|
|
305
|
Use Proxy
|
使用代理。所请求的资源必须通过代理访问
|
|
306
|
Unused
|
已经被废弃的HTTP状态码
|
|
307
|
Temporary Redirect
|
临时重定向。与302类似。使用GET请求重定向
|
|
400
|
Bad Request
|
客户端请求的语法错误,服务器无法理解
|
|
401
|
Unauthorized
|
请求要求用户的身份认证
|
|
402
|
Payment Required
|
保留,将来使用
|
|
403
|
Forbidden
|
服务器理解请求客户端的请求,但是拒绝执行此请求
|
|
404
|
Not Found
|
服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
|
|
405
|
Method Not Allowed
|
客户端请求中的方法被禁止
|
|
406
|
Not Acceptable
|
服务器无法根据客户端请求的内容特性完成请求
|
|
407
|
Proxy Authentication Required
|
请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权
|
|
408
|
Request Time-out
|
服务器等待客户端发送的请求时间过长,超时
|
|
409
|
Conflict
|
服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突
|
|
410
|
Gone
|
客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置
|
|
411
|
Length Required
|
服务器无法处理客户端发送的不带Content-Length的请求信息
|
|
412
|
Precondition Failed
|
客户端请求信息的先决条件错误
|
|
413
|
Request Entity Too Large
|
由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息
|
|
414
|
Request-URI Too Large
|
请求的URI过长(URI通常为网址),服务器无法处理
|
|
415
|
Unsupported Media Type
|
服务器无法处理请求附带的媒体格式
|
|
416
|
Requested range not satisfiable
|
客户端请求的范围无效
|
|
417
|
Expectation Failed
|
服务器无法满足Expect的请求头信息
|
|
500
|
Internal Server Error
|
服务器内部错误,无法完成请求
|
|
501
|
Not Implemented
|
服务器不支持请求的功能,无法完成请求
|
|
502
|
Bad Gateway
|
作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
|
|
503
|
Service Unavailable
|
由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
|
|
504
|
Gateway Time-out
|
充当网关或代理的服务器,未及时从远端服务器获取请求
|
|
505
|
HTTP Version not supported
|
服务器不支持请求的HTTP协议的版本,无法完成处理
|
4-2. 接口异常种类
我们先看下Java异常种类有哪些?
|
Java从Throwable直接派生出Exception和Error。其中Exception是可以抛出的基本类型,在Java类库、方法以及运行时故障中都可能抛出Exception型异常。Exception表示可以恢复的异常,是编译器可以捕捉到的;Error表示编译时和系统错误,表示系统在运行期间出现了严重的错误,属于不可恢复的错误,由于这属于JVM层次的严重错误,因此这种错误会导致程序终止执行。Exception又分为检查异常和运行时异常:
|
|
|
典型的RuntimeException(运行时异常)
|
NullPointerException, ClassCastException(类型转换异常),IndexOutOfBoundsException(越界异常), IllegalArgumentException(非法参数异常),ArrayStoreException(数组存储异常),AruthmeticException(算术异常),BufferOverflowException(缓冲区溢出异常)等
|
|
非RuntimeException(检查异常)
|
包括IOException, SQLException,InterruptedException(中断异常-调用线程睡眠时候),NumberFormatException(数字格式化异常)等
|
Java如何处理异常:try-catch, try-finally, try-catch-finally
介绍几种常见的异常:
1. 空指针:所谓的空指针,就是指针的内容为空,一般在业务测试过程中,就是某个数据未获取到,一般抛出这种异常,日志信息中都会打印的比较全,我们可以通过分析日志来定位到底是什么数据导致的,然后再看这个数据属于脏数据问题,还是说这个数据本身就有可能为null,需要后端进行处理
2. 数据库操作失败
第一个例子:Caused by: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'name' at row 1
第二个例子:Field error in object 'lessonForm' on field 'status': rejected value [fdsa]; codes [typeMismatch.lessonForm.status,typeMismatch.status,typeMismatch.java.lang.Byte,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [lessonForm.status,status]; arguments []; default message [status]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.lang.Byte' for property 'status'; nested exception is java.lang.NumberFormatException: For input string: "fdsa"]
第三个例子:dup key:这个问题一般出现在主键重复,并发测试的时候一般会遇到这种问题
4-3. 接口返回数据错误
这种类型的问题一般都和业务逻辑紧密关联,都是数据返回不正确导致的,对于这种问题一般都要通过数据库查询和代码查询去定位了,比如上面我们说过的例子:开屏广告没有播放:此时定位接口没有返回开屏广告数据,就需要先去数据库查看是否有我们的测试数据,如果数据无误,在查看这个接口具体的方法是什么样的,我们再来看两个例子:
第一个例子:后台系统中某个列表中,分页数据返回为空
我们先看这个问题如何定位:这个列表查询接口第一页返回的数据是正确的,无数据的页面请求传参也没有问题,我们去数据库查询对应的数据发现总共只有一百多条,并不是接口中返回的count:26509,此时我们差不多就定位到问题了:count计算不
如果再深入一下,这个计算为什么不对,我们就要通过代码去查了,通过一步步查询,我们终于定位到sql:发现sql写错了,导致count错误
这个例子是我前两天刚发现并修改的一个bug,感觉比较典型也比较常见
4-4. 接口超时
我们先看造成接口超时的原因会有哪些?对应的处理方式是什么?我觉得这个总结的很好,就直接放了: https://www.jianshu.com/p/6cfb5f2ee4b6

浙公网安备 33010602011771号