新手区 接口自动测试平台搭建踩坑集合

jinglebell · January 14, 2017 · Last by jinglebell replied at January 16, 2017 · 4537 hits

一、背景:

我司之前是没有技术驱动测试或工具驱动测试的历史,绝大部分测试是“界面点点+在数据库手工查看数据”的方式,所以需要开始建设测试技术体系,第一个切入点是做一个通吃公司主流项目的接口自动测试平台。我自己才转测开/自动化方向,难得有这种参与从无到有测试平台搭建的机会,于是看见我司留坑,加上老大肯收留,自己就跳进来了。

二、发帖缘由:

犹豫了很久要不要在社区里发这个贴。社区里关于接口自动测试、接口自动化已经有很多成熟的帖子,无论是实现思路还是底层编码,比我懂的大神有很多,我没必要去造一个已经存在的轮子。但同时我也留意到,社区里关于实现细节的普及贴其实不多而针对实现细节提问的同行不少,所以就想着要不要把自己这两个月踩过的一些坑总结发出来。询问了下老大建议后决定发。这也是第一次在testerhome上发帖,不足或说错的地方请各位大神多多纠正,欢迎带干货地喷,但拒绝为了喷而喷,毕竟在我眼里testerhome是个高大上的测试技术群😀 😀

三、踩坑总结:

第一类坑:跨语言带来的烦恼(业务代码是java,接口测试平台是用python 2.x):

1.1、https参数的加密方式是我司自己写的,并不是公用的md5、3des算法。

理论上:

把对应的java代码拉下来,通过jpype模块去调用对应的类和方法,获取加密后的参数;

实际上:

jpype每次调用都是先启动所在环境的jvm,然后调用相关java类和方法,但是一次python脚本的启动只允许jpype启动关闭一次环境的jvm,第二次启动jvm就会报错(网上找了一整天,没有得到很好的解决方案,老大这种测试专家表示呵呵),但一个接口通常伴随着N个case,一个任务伴随着N个接口,不可能只调用一次java方法来加密参数。

解决方案:

方案一:以beanshell做中转,python先通过命令调beanshell,beanshell去调对应的java文件,把加密后的参数放入公共临时文件(每次临时生成,使用完后当即删除),python再去文件里取数据。可能有人问,为什么不存数据库临时表呢,呵呵说出来可能大家不相信,同环境下同一个java能成功操作mysql,但用beanshell调用相关java时报mysql的driver找不到(我和老大又再次蒙圈。。)。写代码就是这么神奇的事情,永远会有逻辑上解释不通的灵异事件,都知道可能是环境或配置造成的,但你就是不知道环境哪里出错了。
方案二:把java的一些公共方法写到另一个服务端上,python通过http访问该方法,获取服务端返回的加密参数,这是最合适的解决方案,不过我当时没有任何服务端的编程经验,连spring mvc也没使用过,考虑到项目时间成本不可能让我边学、边试、边做,老大说放春节后的重构工作里吧。

1.2、前端和后台数据格式上的协调(前端界面是老司机用js写,后台是我用python2.x写的)

理论上:

前端填写完接口配置信息,把数据丢到mysql,前端操作触发后台开始跑接口测试,python从mysql取出对应的接口配置信息,自动生成案例和对应参数(写入数据库),然后执行每条案例,将返回结果做断言,最后将断言结果、返回结果写入数据库。前端直接从mysql里取出对应信息在前台展示,简直完美!

实际上:

对于json字符串,js和python的处理方式有区别,python是先取出字符串可以直接eval()转dict,随心所欲处理里面的数据,然后str()再转成字符串丢入mysql就行了,但js不行啦,js要把字符串转成json的前提是字符串必须是标准的json字符串,而合法的dict和标准的json字符串之间还是有出入的(单双引号就能引发很多不兼容的血案),所以经常会出现这样的bug,后台获取到接口返回数据(是json格式,只不过用的单引号...),数据不加工直接丢mysql里,前端取出后报错。

解决方案:

和前端老司机多沟通,每次出库把数据处理成python最爽的格式,每次入库前把数据处理成js最爽的方式,字面上看起来简单,但具体磨合,各种replace方法乱入的体验,只有经历过的新手才知道其中的dan疼。

1.3、服务器内部端到端的测试

就说一种情况,校验服务器内部端到端方法时,如果传的参数是个私有类怎么办(绝大部分都是传的一个自定义实体类过去,返回也是返回一个实体类)?
目前没有想好解决方案:按我的理解,这个级别的校验维度基本可以说是代码里的单个函数了,不走功能接口框架,放在白盒框架中实现,和老大讨论后,决定节后再说,先过个好年😆

第二类坑:语言自身底层的缺陷:

2.1 python 2.x的隐式编码(就是不管你的编码格式是utf-8还是其它什么鬼,它都给你显示对应的ascii码,python3.x没这个问题):

理论上:

当我用requests.post获取到接口返回内容时,只要encode成utf-8,那么里面的汉字应该都能正常显示,并存入编码格式同为utf-8的mysql后依然正常显示;

实际上:

汉字部分确实是转成了utf-8,但不好意思,python2.x给你显示的是ascii码,就算加上ascii=False这样的参数都没用,并且存入mysql的依然是ascii码(python2.x的这个坑真的害人不浅啊)。

解决方案:

方案一:
自己写方法将dict转str,将str(已经处理成标准的json格式)存入mysql,ascii码就会转成汉字
eg: {'name':'小今今','age':18},如果是dict格式,无论print还是存mysql,“小今今”都是以ascii码(如u'\xe\xe3')显示,但如果循环这个dict,最后拼成"{'name':'小今今','age':18}"字符串,print和存入mysql,“小今今”能正常显示。
方案二:
少年,换python3.x吧😜

2.2 java更适合处理数据结构已提前知晓的逻辑(针对流程级别的验证是用java实现):

理论上:

我设置一个预期结果(1个标准的json字符串),通过java 的httpclient获取到接口返回的内容(1个标准的json字符串),我直接比较两个json字符串得到断言结果;

实际上:

java不支持对象与对象直接进行比较。退一步,我自己写个方法来比较两个json是否相等,但对于测试平台而言,代码并不知道真实返回的json结构会是什么样子(有哪些key,key的数据类型是什么)。最低级的办法是统一把预期和实际结果的json统一转json字符串比较,但这样隐患很大,哪天返回的json数据顺序改变内容不变,这条case就废了。以前一直吐槽jmeter的断言太不好用了(只能是字符串唯独的比较),但自己遇到这个坑时才发现,jmeter可能是不得不这么做😰

解决方案:

周五前端老司机在网上找到一个用google.json能对比两个json的帖子,准备下周一去试试,但如果后面断言要求我标出具体哪个key不一样,估计就game over了,为什么?因为我司开发返回的数据格式是4层json和list互套。。。结构还TM不统一,第一次看到后瞬间体会思寒大神之前帖子里那句“浮沙上面建高楼”的感觉。

四、结束语:

好啦,在代码层面目前让我觉得疼的坑就这么多,期间也有很多其它问题,但我觉得能自己百度、google、stackoverflow等快速解决的问题,就没必要在这里提了,其实写到这里心中越来越觉得自己编码基础弱,但至少走出了这一步吧,小步慢跑式地成长我觉得最适合自己。另外,说下我自己对接口测试工具尤其是接口自动测试工具的理解吧:
1、接口测试工具的自动程度、使用门槛、通用型、轻量级四者一般得其二,如果自动程度高(自己生成案例、自己提bug、自己锁定异常代码范围等)就必定伴随着定制程度高,基本建立在平台测试开发和业务开发团队之间互相制定的标准上,而且使用者要自己录入的接口配置信息(参数配置、预期结果设置等一系列信息),使用者必须了解最基本的接口测试和该接口底层协议知识,这样的平台也不太可能是脚本级别能做到的。如果通用型高、轻量级,请看jmeter和postman,需要一定使用门槛,在不改写不二次封装的前提下自动程度可以算没有吧。

2、一个公司的测试整体技术水平发展很大程度上依赖这家公司的研发质量水平,之前已经有很多前辈发帖说明此观点,这里不累述。同理,一个公司的测试技术链的搭建很大程度依赖于这个公司整体的IT水平,比如关于落地项目的私钥生成方式、参数加密规则等问题,我和开发沟通了四轮才捋顺,为什么?因为开发发出来的文档、口头说的、代码里最终写的三者两两有出入(研发的沟通机制需要慢慢提高),最要命的是自己写的代码自己说不清楚也是没谁了。总之,未来的路任重而道远吧,求老大赶紧补位一个业内大神过来带我飞呀。

3、第一次发帖就扯这么多,只希望同行看到这篇帖子后,也许能跟自己现在或即将要做的同类项目产生联想或对比,也许能帮助规避或解决一些坑,那么,这篇帖子就发得值了。再不济,就当是给各位看官稍稍展示下一个菜鸟转型测试成长路上的踩坑史吧。

最后声明,因为我不清楚社区具体对帖子的处理规则,所以如果大家要转载也请在不违背社区帖子转载规则的前提下转,谢谢。最后再次提示,由于本人还在菜鸟阶段,要喷请带干货喷,testerhome在我眼中是个高大上的测试技术群😺

共收到 20 条回复 时间 点赞

写的挺认真的
解析json不要用eval 一般都有标准的解析lib的
java如果觉得spring boot重 可以考虑sparkjava 五六行代码即可创建web 长远来看学习spring boot更好

"前端填写完接口配置信息,把数据丢到mysql,前端操作触发后台开始跑接口测试,python从mysql取出对应的接口配置信息"
为啥不是前端js把数据丢给后端python,由python统一读写数据库?这样不就没有json格式的那个问题了?

#2楼 @link1220 当时为了轻快,前端和后台并不是客户端服务端关系,完全分开的,唯一的联系是数据库里共用的数据,和前端执行任务时js启动后台的py文件。而且由于公司人力原因,先是后台开发成型了前端老司机才介入。

#1楼 @seveniruby 好的,后面会慢慢优化

#1楼 @seveniruby spring boot 可是搞小程序的利器

楼主,文章排版还需要考究一点,现在太乱了。

#6楼 @Lihuazhang 好的,下次注意,编辑和预览差好多,但在pc端还能看,没想到在移动端就全乱了,下次不会这样了

#6楼 @Lihuazhang 靠苦口婆心的劝没用 得加个发帖考试的流程了

楼主,很想知道,对于那些业务类型复杂的接口,测试数据只能跑一次,这样我们除了每次从数据库中找数据,还有别的办法吗,

#9楼 @airsen 数据备份和还原,运行脚本前备份数据,结束后数据还原。

—— 来自TesterHome官方 安卓客户端

#9楼 @airsen 单独搭了一个自动化环境用来跑自动化,业务代码和业务测试环境数据会根据具体情况制定同步策略,自动化环境每天会定时回滚一次测试数据库,保持自动化环境里的业务测试数据回到初始状态,否则类似账号注册这样的功能跑完一次就废了,意义不大。

#10楼 @guan_guan2008 我们这边的解决方法和你说的差不多。

#8楼 @seveniruby 我周一也得问下老大,这个格式具体怎么搞。😂

#10楼 @guan_guan2008 咱们公司现在由于 外网环境和正式环境 用的同一个数据库,根本就没有权限,不可能给你权限对正式数据库进行操作的。😂 😂

#11楼 @jinglebell 你们数据库回滚是什么样的策略?是初始全新的数据库?然后备份数据,自动化执行之后,再回滚初始数据吗?

—— 来自TesterHome官方 安卓客户端

#15楼 @tigerge000 初始数据库不是全新的,自动化执行完后再回滚。

Mark,还是棒棒的

请问具体是什么组成的?django?nginx?

#19楼 @caikaibai 不是直接套用的开源框架,和老司机一言不合就两个人自己根据需求写了套伪框架,老司机前端用了spring,我的就算山寨版的mvc吧,某些核心模块用的py的库,比如requests,smtplib,断言也是自己写,只是断言思路参考了业界主流。😂 ,这样老大都没反对。

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up