使用Httprunner在做接口自动化的时候,经常会遇到需要上传文件的场景,下面讲一下关于Httpruner文件上传的用例编写。
1. 建项目
首先我们使用httprunner的脚手架快速搭建一个工程
httprunner --startproject demo
生成的工程目录结构如下图
简单介绍一下这些目录的作用,
- apis ?放接口的目录
- testcases ?放用例的目录
- testsuites ? 放用例集的目录
- reports ? 生成的测试报告目录
- .env ??存放系统环境变量
- debugtalk.py ? 编写动态逻辑函数
2. 抓包与解析
本文使用的是Fiddler抓包工具进行抓的包,访问百度识图网站PC版 ,点击本地上传,选中本地一张图片后上传。那么在Fiddler抓包工具中,我们抓到数据大致如下图所示
选中该接口,点击File->Export Sessions->Selected Sessions, 弹出数据包类型选择,选择HTTPArchive v1.2,给文件命名,这里命名的是upload,那么将得到一个upload.har文件
3. 用例编写
打开DOS,进入到文件所在目录,执行下方命令,将har文件转成yaml文件, 得到文件upload.yml, 文件内容如下图
har2case -2y upload.har
我们注意到,其实这个接口呢,主要就是传递了两个参数值,一个是data,就是图片数据,另一个就是params中的uptime,这是一个13位数的时间戳。其中呢,data数据是可以每次都不变的,但uptime是要随时间变化的,这其实也是一种过滤或者说校验手段,保证每次上传图片的唯一性和有效性。
3.1 处理时间戳问题
关于时间戳呢,在debugtalk.py文件中编写一个获取当前时间戳的动态函数
import time
def getTimeStamp(): # 获取一个13位数的时间戳
return int(time.time()*1000)
将upload.yml文件中的时间戳替换成动态函数之后,就可以无限次数上传刚才上传的那张图片了。更改如下
uptime: ${getTimeStamp()}
3.2 处理图片上传问题
那么如果我们想要上传其他图片呢,思路也是差不多的,只需要把data中的数据换成新的图片的数据即可,也可以像获取时间戳一样写一个带参数path(图片路径)动态逻辑函数,函数读取图片并对图片进行base64编码以及设置boundary,返回编码后的数据。这样相对来说是复杂一些,对于不同的接口编码函数甚至需要更改,为什么呢?我们看到这两张图
-------------------------------------------图片分割线-----------------------------------------------------------
图一显示的就是data在webform中的样子,图二显示的就是data中的raw数据(省略了很多)。从图一和图二我们可以知道,如果要写一个关于读取图片并编码的函数的话,这个函数的返回值中,不仅被要求包含图片的base64格式数据,还要含有其余三个参数的key与其对应的value,就是 tn,image_source, from这三个key,以及他们的值。
写这样的函数其实也不困难,但如果另外一个接口除了图片数据之外又有其它参数要求呢,这个时候就又需要些另外一个编码函数了, 那么有没有更方便一些的方式呢?
有,接着往下看!
前面都是铺垫,下面才是重点,重点,重点!!!
方法一 ? 使用upload关键字
为了方便文件上传呢,Httprunner 2.4.1以上版本支持upload关键字,可以在请求中添加相应参数即可完成图片上传。以刚才的百度图片上传为例,使用关键字upload后的代码是
config: name: testcase description variables: {} teststeps: - name: /upload request: verify: False upload: image: logo.jpg image_source: PC_UPLOAD_FILE tn: pc from: pc headers: Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36 X-Requested-With: XMLHttpRequest method: POST params: uptime: ${getTimeStamp()} url: https://graph.baidu.com/upload validate: - eq: - status_code - 200 - eq: - headers.Content-Type - application/json - eq: - content.is_intervene - false - eq: - content.status - 0 - eq: - content.msg - Success
是不是非常非常简单呢,直接使用upload字段就可以完成编码并上传的功能了。在upload字段下面,我们有四个参数:image, image_source, tn, from。
很眼熟吧,这四个参数就只之前我们提到的那些参数了,其中我们只需要重点关注image, 因为这个key的值是一个file,也就是我们需要上传的文件,所以这里填写的就是我们需要上传的图片的路径。而这个图片路径需要非常注意,它一定是相对于运行路径。以我的项目文件结构为例
如图所示,Logo.jpg文件与api,reports,testcases,testsuites等是处于同一层级的,Logo.jpg和它们都是在根目录demo下的子层级,不要看成属于testsuites了。如果在demo中执行脚本,即命令
hrun api/upload.yml
那么image的值就Logo.jpg。 如果进入到api中执行,即命令
hrun upload.yml
那么image的值就是 ../Logo.jpg, 因为图片在api里的上一层级。这一点需要重点注意!!!
此外呢,可能大家也注意到使用upload字段的脚本下Headers选项中Content-type被删除了,这是因为upload会自动生成对应的Content-type,不需要画蛇添足了,不然遇到各种奇奇怪怪的问题都无从定位。
今天写不动了,也写不完了,明天继续写....