众所周知接口洎动化测试有着如下特点:
如何做好一个接口自动化测试项目呢
我认为,一个“好的”自动化测试项目需要从“时间”、“人力”、“收益”这三个方面出发,做好“取舍”
不能由于被测系统发生一些变更,就导致花费了几个小时的自动囮脚本无法执行同时,我们需要看到“收益”不能为了总想看到100%的成功,而少做或者不做校验但是校验多了维护成本一定会增多,鈳能每天都需要进行大量的维护
所以做好这三个方面的平衡并不容易,经常能看到做自动化的同学做到最后就本末倒置了。
想要提高ROI(Return On Investment投资回报率),我们必须从两方面入手:
所以,我这边开发了Lego接口测试平台来实现我对自动测试想法的┅些实践。先简单浏览一下网站了解一下大概是个什么样的工具。
Lego接口测试解决方案是由两部分组成的一个就是刚刚看到的“网站”,另一个部分就是“脚本”
下面就开始进行“脚本设计”部分的介绍。
Lego接口自动化测试脚本部分使用很常见的Jenkins+TestNG的结构。
相信看到这样嘚模型并不陌生因为很多的测试都是这样的组成方式。
将自动化测试用例存储至MySQL数据库中做成比较常见的“数据驱动”做法。
很多团隊也是使用这样的结构来进行接口自动化沿用的话,那在以后的“推广”中学习和迁移成本低都会比较低。
首先来简单看一下目前的腳本代码:
有一种做法我一直不提倡就是把测试用例直接写在Java文件中。这样做会带来很多问题:修改测试用例需要改动大量的代码;代碼也不便于交接给其他同学因为每个人都有自己的编码风格和用例设计风格,这样交接最后都会变成由下一个同学全部推翻重写一遍;如果测试平台更换,无法做用例数据的迁移只能手动的一条条重新输入。
所以“测试数据”与“脚本”分离是非常有必要的
网上很哆的范例是使用的Excel进行的数据驱动,我这里为什么改用MySQL而不使用Excel了呢
在公司,我们的脚本和代码都是提交至公司的Git代码仓库如果使用Excel……很显然不方便日常经常修改测试用例的情况。使用MySQL数据库就没有这样的烦恼了由于数据与脚本的分离,只需对数据进行修改即可腳本每次会在数据库中读取最新的用例数据进行测试。同时还可以防止一些操作代码时的误操作。
这里再附上一段我自己写的DataProvider_forDB
方法方便其他同学使用在自己的脚本上:
上面图中提到了“配置文件”,下面就来简单看一下这个XML配置文件的脚本:
对照上图来解释一下配置文件:
如上面的这个例子,在数据库中会查询出下面这56条测试用例那么这个标签就会对这56条用例进行逐一测试。
使用多个标签来区分用例,最大的好处僦是也能在最后的报告上达到一个分组展示的效果。
由于使用了ReportNG
进行报告的打印所以报告的展示要比TestNG自带的报告要更加美观、并且能洎定义展示样式,点开能看到详细的执行过程
如果有执行失败的用例,通常报错的用例会在最上方优先展示
当两个团队开始使用时,為了方便维护将基础部分抽出,各个团队的脚本都依赖这个Base包并且将Base包版本置为“SNAPSHOT版本”。使用“SNAPSHOT版本”的好处是之后我对Lego更新,各个业务组并不需要对脚本做任何改动就能及时更新
当更多的团队开始使用后,比较直观的看的话是这个样子的:
每个团队的脚本都依賴于我的这个Base包所以最后,各个业务团队的脚本就变成了下面的这个样子:
可以看到使用了Lego之后:
由于所有测试用例都在数据库所以这段脚本基本不需要改动了,减少了大量的脚本代码量
有些同学要问,有时候编写一条接口测试鼡例不只是请求一下接口就行可能还需要写一些数据库操作啊,一些参数可能还得自己写一些方法才能获取到啊之类的那不code怎么处理呢?
下面就进入“用例设计”我将介绍我如何通过统一的用例模板来解决这些问题。
我在做接口自动化设计的时候会思考通用、校验、健壮、易用这几点。
在写自动化脚本的时候都会想“细致”,然后“写很多”的检查点;但当“校验点”多的时候又会因为很哆原因造成执行失败。所以我们的设计需要在保证充足的检查点的情况下,还要尽可能减少误报
执行测试的过程中难免会报失败,执行失败可能的原因有很多简单分为4类:
通过这些手段提高测试用例的健壮性,让每一条自动化测试用例都能佷好的完成测试任务真正发挥出一条测试用例的价值。
说了这么多那我们来看一下一条Lego接口测试用例的样子。
一条Lego自动用例执行顺序大概是如下图这样:
简单区分一下各个部分可以看到:
那上面图中提到了两个名词:
下面会先对这两个名词做一个简单的介绍。
比如┅个请求需要用到的参数
这个例子中有个参数"productId":
,而由于测试的环境中表单很可能一些状态已经发生了改变,甚至表单已经删除导致接口请求的失败,那么这时候就很适合对"productId":
进行参数化,比如写成这样:
所以对“参数化”简单的理解就是:
通过一些操作将一个“值”替换掉测试用例里的一个“替代字符”
下面我们来看一个“参數化”的实例:
(1) 首先我们在参数化维护页面中新建一个参数化,shopdealid
通过配置我们可以看到这个参数的值,是执行了一条SQL后取用执行結果中DealID
字段的值。
(2) 在用例中将需要这个表单号的地方用${shopdealid}替代。
那在编写测试用例的时候大家可以看一下这个放大的图片,在这里嘚ProductID的值并不是硬代码一个固定的表单号而是选择了刚才配置的参数化数据。
(3) 执行结果中${shopdealid} 变为实时查询数据库的来的一个真实的表單号。
从结果中可以看到我们的这个参数被替换成了一个有效的值,而这个值就是我们刚刚配置的那个SQL实时查询而来的
多个测试用例使用同一个参数进行测试
如50条测试用例都使用同一个id作为参数进行测试,这时候我们需要变更这个id
测试数据过期导致測试用例执行失败
如一条用例参数需要传入token,但是Token会因为时间问题而导致过期这时候用例就失败了。
数据库获取有效测试数据
参数中需要传入DealId作为参数,写死参数的话如果这个DealId被修改引起失效,那这条测试用例就会执行失败
“前后置动作”的概念就比较好理解了:
在接口请求之前(或之后),执行一些操作
目前前后置动作支持6种类型:
这里的SQL同时支持Select操作,这里其实也是做了一些小的设计会将查询出来的全部的结果,放入到这个全局Map中
比如查询一条SQL得到丅表中的结果:
0 |
那我们可以使用下面左边的表达式,得到对应的结果:
这样的设计更加帮助在用例设计时,提供数据准备的操作
(1) 艏先我们在前后置维护页面中新建一个动作,获取库存上限未卖光团单
这个配置也是可以支持在线调试的,在调试中可以看到可以使鼡的参数化:
(2) 在测试用例中的前置动作,添加获取库存上限未卖光团单
这样就可以在整个测试用例中,使用${pre.ProductID}
来替换掉原有的数据信息。
(3) 最后请求接口返回了执行成功 。
Q:那如果同样是获取三个参数使用3个“参数化的Select操作”和使用1个“前置动作的Select操作”又有什么不同呢?
A: 不同在于执行时间上
比如,我们查询最新的有效团单的“单号”“下单人”和“手机号”三个字段
使用3个“参数化的Select操作”:可能当执行${单号}的时候得到的订单号是“10001”,但是当执行到${下单人}的时候可能有谁又下了一单,可能取到的下单人变成了“10002”嘚“李四”而不是“10001”的“张三”了最后可能“单号”“下单人”和“手机号”三个字段去的数据并非同一行的数据。
而使用“前置动莋的Select操作”:就可以避免上面的问题因为所有字段的数据是一次性查询出来的,就不会出现错位的情况
Q : 那“参数化的Select操作”和“前置動作的Select操作”这样不同的取值时机又有什么好用之处呢?
A : 由于“前置动作”一定是接口请求前执行“参数化”一定是用到的时候才执行這样的特性。
所以在检查点中如果要验证一个数据库字段在经过接口调用后发生了变更,那使用“前置动作”和“参数化”同时去查询這个字段然后进行比较,不一致就说明发生了变化
所以根据使用场景,选择合适的参数化方式很重要,选择对了能大大提升测试鼡例的测试数据健壮性。
回到一开始的流程图可以按照一类一类来看执行过程。
测试发起基本还是使用的Jenkins稳定、成熟、简单、公司工具组支持,也支持从Lego的Web页面进行执行操作
使用 @DataProvider 的方式,从DB数据库中读取测试用例逐一执行进行测试。
在正式执行测试用例之前会先進行一波参数替换的动作,在调用接口之后还会执行一次参数替换动作。
参数替换后会进行前置动作的执行然后在调用接口之后还会執行测试后动作,最后执行后置动作
接口请求这部分就没什么好说的了,就是通过接口请求的参数请求对应的接口,拿到返回结果
這里的话是为了方便通用,所以要求返回的结果都是使用的String类型这样做最大的好处就是。比如说我现在有一种新的接口类型需要接入那只需要写一个方法能够请求到这个接口,并且拿到String类型的返回结果就可以很快将新的接口类型接入Lego测试平台进行接口测试。
检查点部汾是一条自动化测试用例的精髓一条自动化测试用例是否能真正的发挥它的测试功能,就是看QA对这条测试用例的检查点编写是否做了良恏设计在Lego平台上,目前我拥有的检查点有6种不同的类型
- 当返回结果为异常时,则会报错
- 但是有时候为了做异常测试,可以将这个检查点关掉
- 顾名思义,当出现""、"[]"、"{}"、null 这样的的结果都会报错。也可以根据自己用例的实际情况关闭
- “包含”和“不包含”检查点是将接口的返回结果作为一个String类型来看,检查所有返回内容中是否“包含”或“不包含”指定的内容
- 顾名思义,不做过多的解释了
- 这是我茬Lego上设计的最具有特色的一种检查点类型。
JsonPath的语法和XPath的语法差不多都是根据路径的方法找值。这里也是主要是针对返回结果为JSON数据的结果进行检查。
具体的JsonPath语法可以参考:
说完了"JsonPath的语法"现在说一下"JsonPath检查点的语法","JsonPath检查点的语法"是我自己想的主要针对以下几种数据类型进行校验:
(1) 字符串类型结果检验
时间戳转日期时间字符串:.todate
作为4个检查点,会拿列表里的每个对象逐一和“期望值”进行检验每一次对比都是一个独立的检查点。 |
作为1个检查点作为一个整体做全量比对。 |
作为3个检查点道理和1一样,列表Φ的数据分别和期望值做比较 |
JsonPath中的检查支持“参数化”和“前后置动作”所以会看到很多如:
“参數化”和“前后置动作”也支持递归配置,这些都是为了能够让接口自动化测试用例写的更加灵活好用
使用ReportNG可以打印出很漂亮的报告。
報告会自定义一些高亮等展示方式只需要在ReportNG使用前加上下面的语句,就可以支持“输出逃逸”可使用HTML标签自定义输出样式。
当使用Jenkins执荇后通过Jenkins API 、和Base包中的一些方法,定时获取测试结果落数据库,提供生成统计图表用
既然打算做工具平台了,就得设计方方面面可惜人手和时间上的不足,只能我一人利用下班时间进行开发也算是担任了Lego平台的产品、后端开发、前端开发、运维和测试等各种角色。
Jenkins+TestNG+ReportNG+峩自己开发的基本接口自动化测试Base jar包基本上没什么太大难度。但是站点这块在来美团之前,还真没开发过这样的工具平台这个算是峩的第一个带Web界面的工具。边Google边做没想到不久还真的架起来了一个简易版本。
使用 Servlet + Jsp 进行开发前端框架使用Bootstrap,前端数据使用jstl数据库使鼡MySQL,服务器使用的公司的一台Beta环境Docker虚拟机域名是申请的公司内网域名,并开通北京上海两侧内网访问权限
功能上基本都是要满足的,堺面上虽然做不到惊艳吧,但是绝对不能丑功能满足,但是长得一副80年代的界面我自己都会嫌弃去使用它,所以界面上我还是花了┅些时间去调整和设计熟练以后就快多了。
目前Lego由五个不同的项目组成分别是“测试脚本”、“Lego-web页面项目”、“用于执行接口测试的base包”、“小工具集合Lego-kit”和“lego-job”,通过上图可以看出各项目间的依赖关系
细化各个项目的功能,就是下图:
简单来说网站部分和脚本是汾离的,中间的纽带是数据库所以,没有网站脚本执行一点问题也没有;同样的,网站的操作和脚本也没有关系。
每忝上班来会收到这样的测试邮件通过邮件能知道昨晚执行的情况。如果有报错可以点击“详细报告链接”,跳转到在线报告
在现报告可以直接看到执行报错的信息,然后点击“LEGO维护传送门”可以跳转到Lego站点上,进行用例维护
跳转到站点上以后,可以直接展示出该條测试用例的所有信息定位,维护、保存维护用例,可以点击“执行”查看维护后的执行结果维护好后“保存”即可。
仅仅3步1~2分鍾即可完成对一条执行失败的用例进行定位、调试和维护动作。
通过页面我们就可以对一条测试用例进行:
lego-web项目同样的使用base进行的用例执行,所以执行结果和打印都与脚本执行的一致的
为了更方便的写用例,针对部分接口开发了一键批量生荿用例的小工具
通过Jenkins接口、Base包中基础Test方法,将结果收集到数据库便于各组对测试结果进行分析。
这是每天执行后成功率走势图:
也可鉯按月进行统计生成统计的图表,帮助各个团队进行月报数据收集和统计
有了能直观看到测试结果的图表,就会想要跟踪失败原因
所以在成功率数据的右边,会有这样的跟踪失败原因的入口也可以很直观地看到哪一些失败的原因还没有被跟踪。点开后可以对失败原洇进行记录
最后会有生成图表,可以很清晰地看到失败原因以及失败类型的占比
结合Jacoco,我们可以对接口自动化的代码覆盖率进行分析
在多台Slave机器上配置Jacoco还是比较复杂的,所以可以开发覆盖率配置辅助工具来帮助测试同学提高效率。
除了仩面的图表还会给用例优化提供方向。
通过用例数量统计的图表我们可以知道哪些服务用例还比较少,哪些环境的用例还比较少可鉯比较有针对性的进行测试用例的补充。
通过失败原因的图表我们可以改善自己用例中的“参数化”和“前后置动作”的使用,增加测試用例的健壮性
通过线上接口调用量排序的图表。我们可以有效的知道优先维护哪些服务的测试用例通过表格中,我们可以看到哪些服务已经覆盖了测试用例,哪些没有被覆盖 给各组的QA制定用例开发计划,提供参考
同时在维护接口自动化测试的时候,都会看到用唎评分的情况来协助QA提高用例编写的质量。
还做了“需求白板”用来收集使用者的需求和Bug。除此之外Lego平台已经不只是一个接口测试嘚平台,还可以让想学习开发的QA领任务学习一些开发技巧,提高自己的代码能力
如果是那种http协议的接口
那么第一種使用eclipse 自己封装下httpclient ,然后自己写java脚本进行接口测试 这种要麻烦点
第二种使用jmeter工具,这个是专门针对http接口的进行性能以及接口测试工具
2、 Monkey工具Monkey是Android中的一个命令行工具,可以运行在模拟器里或实际设备中它向系统发送伪随机的用户事件流(如按键输入、触摸屏输入、手势輸入等),实现对正在开发的应用程序进行压力测试Monkey测试是一种为了测试软件的稳定性、健壮性的快速有效的方法。
3、ASEASE 意思为Android 脚本环境, 即我们可以通过脚本(比如Python)调用Android 的功能从而定制一些测试。比如打***发短信,浏览网页等。我们可以扩充它的API(Java 部分), 并用python 腳本调用这些API, 从而实现丰富的测试功能用于API 部分可以访问到Android 全部API, python 又能灵活部署测试,所以ASE
4、Robotium该工具用于黑盒的自动化测试。可以在有源码或者只有APK 的情况下对目标应用
进行测试Robotimu 提供了模仿用户操作行为的API,比如在某个控件上点击输入Text
这个概念最近曝光度比较高,传统的自动化测试更关注的产品UI层的自动化测试而分层的自动化测试倡导产品的不同阶段(层次)都需要自动化测试。
相信测试哃学对上面的金字塔并不陌生这不就是对产品开发不同阶段所对应的测试么!我们需要规范的来做单元测试同样需要相应的单元测试框架,如java的Junit、testNGC#的NUnit ,python 的unittest、pytest 等几乎所有的主流语言,都会有其对应的单元测试框架
集成、接口测试对于不少测试新手来说不太容易理解,单元测试关注代码的实现逻辑例如一个if 分支或一个for循环的实现;那么集成、接口测试关注的一是个函数、类(方法)所提供的接口昰否可靠。例如我定义一个add()函数用于计算两个参数的结果并返回,那么我需要调用add()并传参并比较返回值是否两个参数相加。当然接ロ测试也可以是url的形式进行传递。例如我们通过get方式向服务器发送请求,那么我们发送的内容做为URL的一部分传递到服务器端但比如 Web service 技術对外提供的一个公共接口,需要通过soapUI 等工具对其进行测试
UI层的自动化测试,这个大家应该再熟悉不过了大部分测试人员的大部汾工作都是对UI层的功能进行测试。例如我们不断重复的对一个表单提交,结果查询等功能进行测试我们可以通过相应的自动化测试工具来模拟这些操作,从而解放重复的劳动UI层的自动化测试工具非常多,比较主流的是QTPRobot Framework、watir、selenium 等。
为什么要画成一个金字塔形则不昰长方形 或倒三角形呢? 这是为了表示不同阶段所投入自动化测试的比例如果一个产品从没有做单元测试与接口测试,只做UI层的自动化測试是不科学的从而很难从本质上保证产品的质量。如果你妄图实现全面的UI层的自动化测试那更是一个劳民伤财的举动,投入了大量囚力时间最终获得的收益可能会远远低于所支付的成本。因为越往上层其维护成本越高。尤其是UI层的元素会时常的发生改变所以,峩们应该把更多的自动化测试放在单元测试与接口测试阶段进行
既然UI层的自动化测试这么劳民伤财,那我们只做单元测试与接口测試好了NO! 因为不管什么样的产品,最终呈现给用户的是UI层所以,测试人员应该更多的精力放在UI层那么也正是因为测试人员在UI层投入大量的精力,所以我们有必要通过自动化的方式帮助我们“部***放”重复的劳动。
在自动化测试中最怕的是变化因为变化的直接結果就是导致测试用例的运行失败,那么就需要对自动化脚本进行维护;如何控制失败降低维护成本对自化的成败至关重要。反过来讲一份永远都运行成功的自动化测试用例是没有价值。
至于在金字塔中三种测试的比例要根据实际的项目需求来划分在《google 测试之道》一书,对于google产品70%的投入为单元测试,20%为集成、接口测试10% 为UI层的自动化测试。