testcase应该是完整且独立的,每条测试用例应该都是可以独立运行的。
首先通过charles对下面操作进行抓包
操作流程:
1.使用账号密码登录
2.新建文档
3.修改文档
使用charles过滤出与本次操作相关的请求数据,导出har包
将har包放到httprunner生成的脚手架项目中,使用har2case xx.har -2y命令解压成yml格式的用例
使用hrun xx.yml运行该用例,此时会运行失败,因为接口之间存在关联数据,而且这些关联数据是动态生成的(如每次执行新建文档都会生成一个新的文档id,后续的修改需要基于此id进行,而用例数据中的文档id是抓包时获取到的当时的id)。所以需要以参数的形式将这些数据进行关联并替换。替换完成后将数据按功能分为三条用例:login.yml、create_doc.yml和change_doc.yml,下面进行用例优化:
场景1:参数化
解决:使用extract将某个接口响应的数据作为参数,可以在其他接口中使用
场景2:用例有流程依赖时(如创建文档时需要先登录)
解决:在teststeps中使用testcase进行调用
场景3:用例有参数依赖时(如修改文档内容时,需要用到创建文档用例中的参数,documentId)
解决:在参数定义文件中使用export导出参数,并在调用文件中使用extract定义导出的参数
登录 login.yml (此处不涉及参数关联,具体内容省略不写了)
创建文档 create_doc.yml
config:name: create doc # 用例名variables: {}verify: false # 开启charles代理时,不校验证书base_url: https://mubu.com # 下面用例中用到的url会自动在base_url基础上扩展teststeps: # 操作步骤- name: logintestcase: testcases/login.yml # 调用登录用例,基于项目根目录使用相对路径【场景2】export: # 导出参数,在其他文件中可以调用 【场景3】- documentId- name: /api/list/create_docrequest:data:folderId: '0'type: '0'headers:content-type: application/x-www-form-urlencoded; charset=UTF-8method: POSTurl: /api/list/create_docextract: # 参数化 【场景1】documentId: content.data.id # 取出响应数据中的documentId- name: /doc${documentId} # 【场景1】通过${documentId}引用上面定义的参数request:headers:user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36(KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36method: GETurl: /doc${memberId} #通过${userId}引用上面定义的参数validate:- eq:- status_code- 200
修改文档 change_doc1.yml
config:name: change docvariables: {}verify: falseteststeps:# 创建文档- name: create documenttestcase: testcases/create_doc.yml # 修改文档前先创建文档,调用用例create_doc.ymlextract: # 【场景3】引用create_doc.yml 中定义的参数,与export对应- documentId# 修改文档- name: /api/middleware/messagerequest:headers:document-id: '${documentId}'request-id: MESSAGE:${userId}:${memberId}:33json:context:appVersion: '0'platform: webdata:documentId: ${documentId}method: POSTurl: https://mubu.com/api/middleware/message
场景4:为了测试修改文档用例,不用像场景3,每次先新建再修改,可以直接使用已经存在的文档进行修改
解决:把文档documentId以全局参数写在文件中
修改文档 change_doc2.yml
config:name: change docvariables: # 【场景4】documentId:cndfvek # 定义全局参数verify: falseteststeps:# 登录- name: logintestcase: testcases/login.yml # 不需要重新创建但修改仍需在登录状态下操作# 修改文档- name: /api/middleware/messagerequest:headers:document-id: '${documentId}'request-id: MESSAGE:${userId}:${memberId}:33json:context:appVersion: '0'platform: webdata:documentId: ${documentId}method: POSTurl: https://mubu.com/api/middleware/message
场景5:httprunner默认对响应结果的一级内容做校验,实际工作中需要对深层次的某些具体响应字段做校验
解决:在validate中使用jsonpath定位字段进行校验,了解更多校验使用,参考https://debugtalk.com/post/HttpRunner-validator-optimization/
对response中的username进行校验
validate:- eq:- content.data.documents.0.userName- tingjio
base_url的使用
场景:httprunner中提供了base_url,用例步骤中用到的url会自动在base_url基础上扩展,有些用例中包含多个url
解决:方法一:如果用例中需要用到多个url时,将url路径写全,则不会采用base_url的值
config:name: create doc # 用例名variables: {}base_url: https://mubu.com # 下面用例中用到的缺省url会自动在base_url基础上扩展teststeps:- name: emo1request:method: POSTurl: https://baidu.com # 全路径不会采用base_url的值- name: demo2request:method: POSTurl: /list # 在base_url基础上扩展
方法二:将多个url以不同的参数名定义在variables中,分别调用
config:name: create doc # 用例名variables:url1: https://api.mubu.com # 有多个url时,可以在变量中定义url2: https://test.mubu.comurl3: https://mubu.comteststeps:- name: emo1request:method: POSTurl: ${url1}- name: demo2request:method: POSTurl: ${url2}
场景:正式/测试环境切换
解决:在debugtalk.py中定义切换函数,用例中调用切换函数
debugtalk.py
def get_base_url(env_type="prod"):if env_type == 'prod':return 'https://mubu.com'else:return 'https://test.mubu.com'
login.yml
config:name: loginvariables: {}verify: falsebase_url: ${get_base_url(test)} # 使用测试环境
使用环境变量env存储隐私变量
场景:测试用例涉及到登录时,登录账号和密码会以明文暴露在用例中,提交后会造成信息泄漏
解决:将隐私信息保存在env文件中,提交代码时不提交该文件,使用用例的人自己配置该文件
.env文件
USERNAME=18691335588PASSWORD=zhouting414
login.yml
- name: demorequest:data:password: ${ENV(PASSWORD)} # 引用环境变量phone: ${ENV(USERNAME)}......
