pytest+yaml实现接口自动化框架之用例参数关联(二)

发表于:2021-5-27 09:28  作者:上海-悠悠   来源:博客园

字体: | 上一篇 | 下一篇 |我要投稿 | 推荐标签: pytest 单元测试

  前言
  使用 yaml 文件写测试用例的时候,如何在 yaml 文件的测试用例里面实现参数关联? 这是很多做自动化测试的小伙伴经常思考的一个问题。
  接着前面的pytest+yaml 文件实现接口自动化框架,本篇使用环境变量的方式,让测试用例参数关联。
  实现场景:上个接口返回的接口提取变量,在写个接口中引用变量。
  场景案例
  我现在有一个登陆接口A,登陆成功后返回一个token值。有一个获取用户信息的接口B,但是接口B必须要先登录后传登录的token才能访问。
  A接口登录接口文档基本信息
  访问地址:http://127.0.0.1:8000/api/v1/login/
  请求类型:POST
  请求头部:application/json
  请求参数:{"username":"test", "password":"123456"}
  B接口获取绑定卡号的接口文档基本信息
  访问地址:http://127.0.0.1:8000/api/v1/userinfo/
  请求类型:GET
  请求头部:Content-Type: application/json
  请求头部token参数: Authorization: Token xxxxx login token xxxxx
  先不带token去访问接口B,使用命令行工具httpie测试接口
  C:\Users\dell>http http://127.0.0.1:8000/api/v1/user/info/
  HTTP/1.1 401 Unauthorized
  Allow: GET, POST, HEAD, OPTIONS
  Content-Length: 58
  Content-Type: application/json
  Date: Sat, 21 Sep 2019 14:06:15 GMT
  Server: WSGIServer/0.2 CPython/3.6.0
  Vary: Accept
  WWW-Authenticate: Token
  X-Frame-Options: SAMEORIGIN
  {
      "detail": "Authentication credentials were not provided."
  }
  不带token会提示没权限访问:401 Unauthorized。
  先使用接口测试工具测试下,用postman,或者fiddler都可以,我这里为了查看报文信息方便,用httpie命令行工具。
  先访问接口A获取token值234af73571da46ade79ea6a74961b1d23d609b79
  D:\>http http://127.0.0.1:8000/api/v1/login/ username=test password=123456 -v
  POST /api/v1/login/ HTTP/1.1
  Accept: application/json, */*
  Accept-Encoding: gzip, deflate
  Connection: keep-alive
  Content-Length: 42
  Content-Type: application/json
  Host: 127.0.0.1:8000
  User-Agent: HTTPie/1.0.3
  {
      "password": "123456",
      "username": "test"
  }
  HTTP/1.1 200 OK
  Allow: POST, OPTIONS
  Content-Length: 109
  Content-Type: application/json
  Date: Sat, 21 Sep 2019 15:37:06 GMT
  Server: WSGIServer/0.2 CPython/3.6.0
  Vary: Accept, Cookie
  X-Frame-Options: SAMEORIGIN
  {
      "code": 0,
      "msg": "login success!",
      "token": "234af73571da46ade79ea6a74961b1d23d609b79",
      "username": "test"
  }
  传给下个接口B
请  D:\>http http://127.0.0.1:8000/api/v1/user/info/ Authorization:"Token b7e02c959fbae4c2a0d9094f6f9b9a35fa8aaa1e" -v
  GET /api/v1/user/info/ HTTP/1.1
  Accept: */*
  Accept-Encoding: gzip, deflate
  Authorization: Token b7e02c959fbae4c2a0d9094f6f9b9a35fa8aaa1e
  Connection: keep-alive
  Host: 127.0.0.1:8000
  User-Agent: HTTPie/1.0.3
  HTTP/1.1 200 OK
  Allow: GET, POST, HEAD, OPTIONS
  Content-Length: 96
  Content-Type: application/json
  Date: Sat, 21 Sep 2019 16:04:25 GMT
  Server: WSGIServer/0.2 CPython/3.6.0
  Vary: Accept
  X-Frame-Options: SAMEORIGIN
  {
  "msg": "sucess!",
  "code": 0,
  "data": [{
  "id": 15,
  "name": "test",
  "sex": "F",
  "age": 20,
  "mail": "1122@qq.com",
  "create_time": "2020-12-18"
  }]
  }
  传头部参数用xx:xxxx格式,中间用冒号:,如:User-Agent:demo-agent/1.0 'Cookie:a=b;b=c' ,由于Authorization参数中间有空格,用双引号包起来。
  conftest.py 代码实现
  在 conftest.py 使用环境变量保存测试的结果提取的变量,使用 template 替换 yaml 文件的变量。
  import pytest
  import requests
  import jsonpath
  import json
  import yaml
  from string import Template
  import os
  # 作者-上海悠悠 QQ交流群:717225969
  # blog地址 https://www.cnblogs.com/yoyoketang/
  def pytest_collect_file(parent, path):
      # 获取文件.yml 文件,匹配规则
      if path.ext == ".yml" and path.basename.startswith("test"):
          print(path)
          print(parent)
          return YamlFile(path, parent)
  class YamlFile(pytest.File):
      '''收集测试用例'''
      def collect(self):
          yml_raw = self.fspath.open(encoding='utf-8').read()
          yml_var = Template(yml_raw).safe_substitute(os.environ)
          yaml_data = yaml.safe_load(yml_var)
          for yaml_case in yaml_data:
              name = yaml_case.get("test").get("name")
              values = yaml_case.get("test")
              yield YamlTest(name, self, values)
  class YamlTest(pytest.Item):
      def __init__(self, name, parent, values):
          super(YamlTest, self).__init__(name, parent)
          self.name = name
          self.values = values
          self.s = requests.session()
      def values_render_variable(self, values):
          # values 是Test用例部分
          yaml_test = Template(json.dumps(values)).safe_substitute(os.environ)
          values = yaml.safe_load(yaml_test)
          return values
      def runtest(self):
          # 运行用例
          values = self.values_render_variable(self.values)
          request_data = values.get("request")
          print("\n请求数据: ", request_data)
          print(request_data)
          response = self.s.request(**request_data)
          print("接口返回", response.text)
          # 判断是否有extract提取参数
          if values.get("extract"):
              for key, value in values.get("extract").items():
                  os.environ[key] = jsonpath.jsonpath(response.json(), value)[0]
          self.assert_response(response, values.get("validate"))
      def assert_response(self, response, validate):
          '''设置断言'''
          if validate:
              for i in validate:
                  if "eq" in i.keys():
                      yaml_result = i.get("eq")[0]
                      actual_result = jsonpath.jsonpath(response.json(), yaml_result)
                      expect_result = i.get("eq")[1]
                      print("实际结果:%s" % actual_result[0])
                      print("期望结果:%s" % expect_result)
                      assert actual_result[0] == expect_result
  YAML 文件案例
  使用 extract 关键字提取变量,提取变量方式执行jsonpath表达式, 引用变量使用template 模板的引用语法$变量名。
  # 作者-上海悠悠 QQ交流群:717225969
  # blog地址 https://www.cnblogs.com/yoyoketang/
  - test:
      name: login case1
      request:
          url: http://49.235.X.X:7000/api/v1/login/
          method: POST
          headers:
              Content-Type: application/json
              User-Agent: python-requests/2.18.4
          json:
              username: test
              password: 123456
      extract:
          token: $.token
      validate:
          - eq: [$.msg, login success!]
          - eq: [$.code, 0]
  - test:
      name: get user info case1
      request:
          url: http://49.235.X.X:7000/api/v1/userinfo/
          method: GET
          headers:
              Content-Type: application/json
              User-Agent: python-requests/2.18.4
              Authorization: Token $token
      validate:
          - eq: [$.code, 0]
          - eq: ["$.data[0].name", test]
          - eq: ["$.data[0].mail", 1122@qq.com]
  执行结果
  执行方式使用命令行运行,支持pytest的命令行指令。
  运行结果:
  >pytest -s
  ============================= test session starts ==============================
  platform win32 -- Python 3.6.6, pytest-4.5.0, py-1.9.0, pluggy-0.13.1
  rootdir: D:\soft\api_pytest_1208
  collecting ... D:\soft\api_pytest_1208\data\test_info.yml
  <Package D:\soft\api_pytest_1208\data>
  collected 2 items
  data\test_info.yml
  请求数据:  {'url': 'http://49.235.X.X:7000/api/v1/login/', 'method': 'POST', 
  'headers': {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4'}, 
  'json': {'username': 'test', 'password': 123456}}
  {'url': 'http://49.235.X.X:7000/api/v1/login/', 'method': 'POST', 
  'headers': {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4'},
   'json': {'username': 'test', 'password': 123456}}
  接口返回 {"code": 0, "msg": "login success!", "username": "test", "token": "09be4368534fa6320ed77a333e34c6661a36d40e"}
  实际结果:login success!
  期望结果:login success!
  实际结果:0
  期望结果:0
  .
  请求数据:  {'url': 'http://49.235.X.X:7000/api/v1/userinfo/', 'method': 'GET', 
  'headers': {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4', 
  'Authorization': 'Token 09be4368534fa6320ed77a333e34c6661a36d40e'}}
  {'url': 'http://49.235.X.X:7000/api/v1/userinfo/', 'method': 'GET', 
  'headers': {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4', 
  'Authorization': 'Token 09be4368534fa6320ed77a333e34c6661a36d40e'}}
  接口返回 {"msg":"sucess!","code":0,"data":[{"id":15,"name":"test","sex":"F","age":20,"mail":"1122@qq.com","create_time":"2020-12-18"}]}
  实际结果:0
  期望结果:0
  实际结果:test
  期望结果:test
  实际结果:1122@qq.com
  期望结果:1122@qq.com
  .
  =========================== 2 passed in 0.49 seconds ===========================

      本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理

评 论

论坛新帖



建议使用IE 6.0以上浏览器,800×600以上分辨率,法律顾问:上海信义律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2021, 沪ICP备05003035号
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪公网安备 31010102002173号

51Testing官方微信

51Testing官方微博

扫一扫 测试知识全知道