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

  1. config:
  2. name: create doc # 用例名
  3. variables: {}
  4. verify: false # 开启charles代理时,不校验证书
  5. base_url: https://mubu.com # 下面用例中用到的url会自动在base_url基础上扩展
  6. teststeps: # 操作步骤
  7. - name: login
  8. testcase: testcases/login.yml # 调用登录用例,基于项目根目录使用相对路径【场景2】
  9. export: # 导出参数,在其他文件中可以调用 【场景3】
  10. - documentId
  11. - name: /api/list/create_doc
  12. request:
  13. data:
  14. folderId: '0'
  15. type: '0'
  16. headers:
  17. content-type: application/x-www-form-urlencoded; charset=UTF-8
  18. method: POST
  19. url: /api/list/create_doc
  20. extract: # 参数化 【场景1】
  21. documentId: content.data.id # 取出响应数据中的documentId
  22. - name: /doc${documentId} # 【场景1】通过${documentId}引用上面定义的参数
  23. request:
  24. headers:
  25. user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36
  26. (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36
  27. method: GET
  28. url: /doc${memberId} #通过${userId}引用上面定义的参数
  29. validate:
  30. - eq:
  31. - status_code
  32. - 200

修改文档 change_doc1.yml

  1. config:
  2. name: change doc
  3. variables: {}
  4. verify: false
  5. teststeps:
  6. # 创建文档
  7. - name: create document
  8. testcase: testcases/create_doc.yml # 修改文档前先创建文档,调用用例create_doc.yml
  9. extract: # 【场景3】引用create_doc.yml 中定义的参数,与export对应
  10. - documentId
  11. # 修改文档
  12. - name: /api/middleware/message
  13. request:
  14. headers:
  15. document-id: '${documentId}'
  16. request-id: MESSAGE:${userId}:${memberId}:33
  17. json:
  18. context:
  19. appVersion: '0'
  20. platform: web
  21. data:
  22. documentId: ${documentId}
  23. method: POST
  24. url: https://mubu.com/api/middleware/message

场景4:为了测试修改文档用例,不用像场景3,每次先新建再修改,可以直接使用已经存在的文档进行修改
解决:把文档documentId以全局参数写在文件中

修改文档 change_doc2.yml

  1. config:
  2. name: change doc
  3. variables: # 【场景4】
  4. documentIdcndfvek # 定义全局参数
  5. verify: false
  6. teststeps:
  7. # 登录
  8. - name: login
  9. testcase: testcases/login.yml # 不需要重新创建但修改仍需在登录状态下操作
  10. # 修改文档
  11. - name: /api/middleware/message
  12. request:
  13. headers:
  14. document-id: '${documentId}'
  15. request-id: MESSAGE:${userId}:${memberId}:33
  16. json:
  17. context:
  18. appVersion: '0'
  19. platform: web
  20. data:
  21. documentId: ${documentId}
  22. method: POST
  23. url: https://mubu.com/api/middleware/message

场景5:httprunner默认对响应结果的一级内容做校验,实际工作中需要对深层次的某些具体响应字段做校验
解决:在validate中使用jsonpath定位字段进行校验,了解更多校验使用,参考https://debugtalk.com/post/HttpRunner-validator-optimization/

对response中的username进行校验
image.png

  1. validate:
  2. - eq:
  3. - content.data.documents.0.userName
  4. - tingjio

base_url的使用

场景:httprunner中提供了base_url,用例步骤中用到的url会自动在base_url基础上扩展,有些用例中包含多个url
解决:方法一:如果用例中需要用到多个url时,将url路径写全,则不会采用base_url的值

  1. config:
  2. name: create doc # 用例名
  3. variables: {}
  4. base_url: https://mubu.com # 下面用例中用到的缺省url会自动在base_url基础上扩展
  5. teststeps:
  6. - name: emo1
  7. request:
  8. method: POST
  9. url: https://baidu.com # 全路径不会采用base_url的值
  10. - name: demo2
  11. request:
  12. method: POST
  13. url: /list # 在base_url基础上扩展


方法二:将多个url以不同的参数名定义在variables中,分别调用

  1. config:
  2. name: create doc # 用例名
  3. variables:
  4. url1: https://api.mubu.com # 有多个url时,可以在变量中定义
  5. url2: https://test.mubu.com
  6. url3: https://mubu.com
  7. teststeps:
  8. - name: emo1
  9. request:
  10. method: POST
  11. url: ${url1}
  12. - name: demo2
  13. request:
  14. method: POST
  15. url: ${url2}

场景:正式/测试环境切换
解决:在debugtalk.py中定义切换函数,用例中调用切换函数
debugtalk.py

  1. def get_base_url(env_type="prod"):
  2. if env_type == 'prod':
  3. return 'https://mubu.com'
  4. else:
  5. return 'https://test.mubu.com'

login.yml

  1. config:
  2. name: login
  3. variables: {}
  4. verify: false
  5. base_url: ${get_base_url(test)} # 使用测试环境

使用环境变量env存储隐私变量

场景:测试用例涉及到登录时,登录账号和密码会以明文暴露在用例中,提交后会造成信息泄漏
解决:将隐私信息保存在env文件中,提交代码时不提交该文件,使用用例的人自己配置该文件

.env文件

  1. USERNAME=18691335588
  2. PASSWORD=zhouting414

login.yml

  1. - name: demo
  2. request:
  3. data:
  4. password: ${ENV(PASSWORD)} # 引用环境变量
  5. phone: ${ENV(USERNAME)}
  6. ......