移动测试开发 Httprunner2 实战踩坑记录

opentest-oper@360.cn · 2022年06月30日 · 最后由 Thirty-Thirty 回复于 2022年07月01日 · 5472 次阅读

基于 Httprunner(2.5.7 版本)的接口自动化,在我们项目上持续运用、打磨了近 2 年的时间,把使用过程中的一些心得/遇到的问题及对应的解决方案/思路,做一个介绍(目前我们项目 case 规模 2400+,运行时长 1 分钟左右,成功率 99.99%,见下图)

效率是不是很不错?问题主要包含如下几类:

一、错误提示:exception stage: parse tests

1.问题描述
这个错误是使用 httprunner 过程中经常遇到的,出现这个错误的场景非常多,都是对 yaml 文件解析出现了错误。
2.产生问题的可能原因:
①. yaml 中使用了未定义的变量。
②. 在使用变量时未使用符号 $。
③. 在调用 debugtalk.py 中的方法时缺少{}或者()。
④. 格式问题,相同的层级的变量,缩进不同。
⑤. 引用的参数定义错误
在解析 yaml 文件中通过符号 $ 引用的变量时,在源文件 parser.py 中,会对变量进行校验,只取以 $ 开头 + 字母数字下划线的部分。
如下,在 yaml 文件中引用了一个变量 $title-tup

在对这个文件进行解析时,会对名称 $title-tup 进行正则校验,校验完后变量就变成了 $title,如下图所示,而实际文件中是找不到这个变量 $title 对应的值的,所以就会出现错误。

二、错误提示:ResponseObject does not have attribute: parsed_body

1.问题描述:
如果在 yaml 文件中使用了 jsonpath 提取器提取要校验的内容,此时有可能会报上述错误
2.产生问题的原因:
ResponseObject 找不到 parsed_body 属性,这是框架本身的一个小 BUG,但是这个框架作者一直没去维护更新。
3.解决方案:
找到 httprunner 源码 response.py 文件, 将第 62 行 self.parsed_body() 改成 self.json。

三、断言没有执行,也没有报错

1.问题描述:
当你的接口返回值是一个集合或者 list 等,需要判断结果中包含某些值时,可能会在 yaml 中写多个 contains 断言,这些断言的方法相同,要校验的值 check 也相同,只有期望值 expect 不同,此情况下你会发现这样的校验在报告中只记录了最后一条断言的结果,如下图所示:

执行结果:

2.产生问题原因:
由于在 api 文件中,可能会定义一些默认的断言,在 testcases 文件中引用 api 中的 yaml 文件时,可能会存在与 api 文件中相同的响应的断言,为了使得 2 文件对相同部分的断言不重复,在 httprunner 的源码 parser.py 文件中,对断言信息进行解析时,会将断言的方法以及 check 信息合并到一起作为一个 key,expect 作为值赋给一个字典,循环所有的断言,当遇到第一个 contains 时,会在字典中添加这个 key,并赋值为 $fwed1,当循环到第二个 contains 断言时,字典中有相同的 key 了,就会把字典中的值修改为 $fwed2,这样就导致在实际执行时,第一个 contains 断言没有执行,只执行了第二个 contains 断言。源码如下:

3.解决方案:
①. 如果 check 可以取到更细粒度的值,那么直接取到要断言的值,保证断言的方法以及 check 都不重复。
②. 如果要 check 的值是无序的,无法精确取到下一层级的值,可以在 debugtalk.py 中自定义一个新的方法,对集合进行整体进行校验。

四、错误提示:Failed to extract attribute from response!

遇到这个错误,多数是以下两种原因:
1.接口返回的数据跟期望的不一样,你要提取的变量不存在,此时要检查一下是不是接口出错了,或者提取信息写错了。
2.断言第一个参数里不包含从接口响应中提取的值。
①. 问题描述:
如下图所示,断言方法 check_sql 中第一个参数中不包含从响应中提取的值,就会出错。

②. 解决方案:
修改断言的第一个参数值,参数中包含从响应中提取的值

五、自定义方法形参问题

1.自定义方法作为断言方法,形参格式应该跟内置的断言方法保持一致:
①. 形参个数要求是 2 个
②. 第一个形参是要 check 的值,第二个是 expect 值,二者不可以错位。
2.通过 $ 去调用自定义函数时,如果传入的参数是字符串,这个参数不可以用引号引起来。
①. 问题描述:
如下图所示,自定义函数 update_redis,函数形参是一个字符串类型,所以在 yaml 文件中传值时,传入了一个 key,类型是字符串类型,用双引号引起来了。实际执行这条用例时,这个方法就会被忽略掉,不执行。

②. 产生问题原因:
当解析到这个方法时,在 parser.py 文件中会通过正则表达式进行校验来判断此处是一个函数还是一个参数,如下图,判断是否是一个函数,规则如下:

从上述匹配规则可以看出来,匹配的是以 ${开头,}结尾的,中间可以包含数字、字母、下划线、$、-、.、= ,当用例中函数参数加了引号就会被标记为非 function 类型,实际运行时就不会执行函数调用了。
③. 解决方案:
方案一:直接写变量,不用引号,函数调用时,就是字符串类型。

方案二:定义一个变量,引用此变量。

六、多线程实现:

当 case 量很大时(如千级别及以上规模),原有单进程的方式,case 执行时长通常是难以接受的。为此,研究源码发现,只需修改源码根目录中的 api.py 文件中的_run_suite 方法,用如下代码替换:

说明:

  1. 其中 max_workers 代表线程池数量
  2. 需要导入如下包
from concurrent.futures.thread import ThreadPoolExecutor
from concurrent import futures
  1. 使用多线程的话,建议一个接口的用例放在同一个 yml 文件中,接口与接口之间用例要解耦

七、提高报告的打开效率

当 case 量很大时,如果报告中展示全量 case 执行结果的话,报告本身打开也会非常慢,并且失败的 case 查找也很费劲,实战中建议大家报告中只展示失败的 CASE(通常应该会非常少)。较为简单的修改方法是,copy 一份源码目录中 httprunner/report/template.html(例如命名为 template_fail.html),增加成功 case 的过滤功能,如下图:

说明:
1.上图只截取了开始标签,结尾注意标签的闭合
2.用例执行的时候加上—report-template=template_fail.html(建议使用绝对路径)参数,不加的话,还是默认展示全量 case

八、总结

Httprunner 的简介中说到,HttpRunner 是一款面向 HTTP(S) 协议的通用测试框架,只需编写维护一份 YAML/JSON 脚本,即可实现自动化测试,但是当你真正使用时,会发现仅仅会用其定义好的关键字、断言方法并不能满足我们的需求,且会遇到各种各样的问题,当你遇到百度不出来,各种尝试也找不到问题原因时,可以通过 debug 源码来找到问题的答案。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 1 条回复 时间 点赞

标题给力,末尾总结到位

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