接口测试框架实践:用例管理模块

发表于:2024-2-21 09:07

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:软件质量保障    来源:知乎

  本文中测试用例是测试数据(文件)+ 测试用例(文件)的统称。本文介绍的框架利用yaml文件存储测试用例。
  1.1 用例规范
  无规矩不成方圆,规范有很多好处。
  ·易读性高
  · 易于批量生成测试用例等
  · 维护成本高
  测试用例文件命名规则
  (1)测试用例遵循以下原则:
  ·文件名以 test_*.py 文件和*_test.py
  · 以 test_ 开头的函数
  · 以 Test 开头的类,不能包含 __init__ 方法
  · 以 test_ 开头的类里面的方法
  · 所有的包 pakege 必须要有__init__.py 文件
  (2)测试用例文件的命名要突出测试功能,让别人一眼看到名字就能知道被测功能
  例如:测试支付模块,则可以命名为test_payment_case_001.py
  对于这块,一千个人心中可能有一千个哈姆雷特,核心原则就是 一眼能望穿功能 即可。
  (3)测试数据文件命名规则
  1. 测试数据一般固定存档至固定文件夹下
  2. 文件命名要与测试逻辑文件有对应关系。
  3. 测试数据文件的名字建议全大写命名
  4. 测试数据可以根据测试要素拆分成:用例id, 用例HTTP部分,断言部分。
  1.2测试数据文件模板
  在我的文章接口测试中也有详细的介绍,接口测试通常报告功能性测试、非功能性测试。
  功能性测试主要涉及单接口测试、接口组合场景测试。
  单接口测试主要围绕接口的参数、幂等展开;场景用例主要涉及多接口间的组合,更多涉及到接口间参数传递。
  针对这两种不同的测试场景,我将测试数据模板分为两种:单接口、组合场景测试模板。
  单接口测试数据模板
  - case: 测试登陆001
    http:
      method: POST
      path: https://account.xinli001.com/login
      headers:
        Content-Type: application/json; charset=UTF-8
        X-Requested-With: XMLHttpRequest
      body:
        password: xxxxx
        username: xxxxx@163.com
    expected:
      response:
        message: 登陆成功
      DB:
      code: 0
        
  - case: 测试登陆002
    http:
      method: POST
      path: https://account.xinli001.com/login
      headers:
        Content-Type: application/json; charset=UTF-8
        X-Requested-With: XMLHttpRequest
      body:
        password: xxxxx
        username: xxxxx@163.com
    expected:
      response:
        message: 登陆成功
      DB:
      code: 0
  多接口组合测试数据模板
  - case: 测试登陆查询回答内容001
    http:
      login:
        method: POST
        path: https://account.xinli001.com/login?next=https://www.xinli001.com/user
        headers:
          Content-Type: application/json; charset=UTF-8
          X-Requested-With: XMLHttpRequest
        body:
          password: xxxxx
        username: xxxxx@163.com
      query:
        method: GET
        path: https://m.xinli001.com/get-my-answers.json
        headers:
          User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36
        body:
          payload:
    expected:
      response:
        message: 登录成功
        code: 0
  组合接口模板包含两条HTTP请求的数据,login和query接口的请求数据。
  有了测试数据,下面就结合测试用例进行实践。
  conftest.py
  登陆前置动作,可以放置该文件中,作为setup使用。
  #!/usr/bin/env python
  # -*- encoding: utf-8 -*-
  '''
  @Time    :   2021/06/20 12:07:09
  @Author  :   软件质量保障
  @wechat  :   ISTE1024
  @Email   :   byteflow@163.com
  @Blog    :   https://www.zhihu.com/people/iloverain1024
  @Copyright : 侵权必究
  '''
  import pytest
  import yaml
  import requests
  # 封装好的HTTP请求类
  class RequestHandler:
      def __init__(self):
          """session管理器:维持会话,可以让我们在跨请求时保存某些参数"""
          self.session = requests.session()
      def httpcore(self, method, url, params=None, data=None, json=None, headers=None, **kwargs):
          return self.session.request(method,url, params=params, data=data, json=json, headers=headers,**kwargs)
      def close_session(self):
          """关闭session"""
          self.session.close()
  @pytest.fixture(scope='function')
  def login():
      data = yaml.safe_load(open('/testcases/data/TEST_LOGIN.yaml', encoding='utf-8'))
      http = data['http']
      method = http["method"]
      url = http["path"]
      headers = http["headers"]
      json = http["body"]['payload']
      req = RequestHandler()
      req.httpcore(method, url=url, headers=headers, data=json)
      return req
  登陆接口对应的测试数据文件为TEST_LOGIN.yaml
  http:
      method: POST
      path: https://account.xinli001.com/login?next=https://www.xinli001.com/user
      headers:
        Content-Type: application/x-www-form-urlencoded; charset=UTF-8
        X-Requested-With: XMLHttpRequest
      body:
        payload: password=xxxxx&username=xxxxxx%40163.com
  expected:
    response:
      message: 登陆成功
      code: 0
  测试用例文件 test_function_002.py
  #!/usr/bin/env python
  # -*- encoding: utf-8 -*-
  '''
  @Time    :   2021/06/20 12:07:09
  @Author  :   软件质量保障
  @wechat  :   ISTE1024
  @Email   :   byteflow@163.com
  @Blog    :   https://www.zhihu.com/people/iloverain1024
  @Copyright : 侵权必究
  '''
  import pytest
  import yaml
  # 用例重载
  def data_reload(request, data_key):
      data = request[data_key]
      method = data["method"]
      url = data["path"]
      headers = data["headers"]
      body = data["body"]
      return method, url, headers, body
  # 用例集读取
  def get_test_data(test_data_path):
      case = []  # 存储测试用例名称
      http = []  # 存储请求对象
      expected = []  # 存储预期结果
      data = yaml.safe_load(open(test_data_path, encoding='utf-8'))
      for td in data:
          case.append(td.get('case', ''))
          http.append(td.get('http', {}))
          expected.append(td.get('expected', {}))
      parameters = zip(case, http, expected)
      return list(parameters)
  @pytest.mark.parametrize("case, http, expected", get_test_data('/testcases/data/TEST_DATA_002.yaml'))
  def test_main(case, http, expected, login):
      # 数据准备,这块可以再单独封装一层
      method, url, headers, body = data_reload(http, 'query')
      # 发起请求
      query_res = login.httpcore(method, url=url, headers=headers, data=body)
      print(query_res.json())
      # 断言
      assert query_res.json()['code'] == expected['response']['code']
  对应的测试数据文件TEST_DATA_002.yaml
  - case: 测试登陆查询回答内容001
    http:
      login:
        method: POST
        path: https://account.xinli001.com/login?next=https://www.xinli001.com/user
        headers:
          Content-Type: application/x-www-form-urlencoded; charset=UTF-8
          X-Requested-With: XMLHttpRequest
        body:
          payload: password=xxxx&username=xxxxx%40163.com
      query:
        method: GET
        path: https://m.xinli001.com/get-my-answers.json
        headers:
          User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36
        body:
          payload:
    expected:
      response:
        message: 登录成功
        code: 0
  我们执行测试看一下效果:
  1.3用例自动生成
  测试用例自动化生成已经不算什么高深的技术了。作者在前东家工作时候就有过自动化用例生成的实践,并且有产出专利。我认为 用例生成的核心思想就是 数据源+用例模板化+模板引擎。正如上述我们介绍的单接口、组合接口模板,我们可以归类所有POST请求可以共用一套模板,所有GET请求可以共用一套模板,其他请求方法类似。当然亦可以汇总所有请求方法为同一个模板中;而数据源可以来源于POSTMAN导出的JSON文件、SWAGGER文档,Charles的Har文件,甚至JMeter的JMX文件,当然我们需要写解析这些文件的脚本才能获取到需要的数据。而模板引擎可以使用FreeMarker。
  (1)测试数据生成
  圈红处的可以作为变量值,从数据源中提取出来并填充到key键的值。
  (2)测试用例生成
  而测试用例文件中,上述圈红处可以作为变量,从数据源中提取需要的数据进行填充。
  1.4用例维护
  我们的自动化用例不是一成不变的,恰恰相反,自动化用例是需要经常维护更新的。这也是自动化用例的成本所在:维护成本。如果维护成本过高,那就不建议考虑着手自动化。而如何降低维护成本也是自动化测试需要重要关注的。
  根据不同项目不同功能点,我们可以按以下维度实行用例管理。
  (1)按组
  (2)标签
  (3)测试类型
  而Pytest自身提供pytest.mark用于标记用例属性。具体实践如下:
  配置pytest.ini文件:
  [pytest]
  xfail_strict = true
  addopts=-vqs --html=./report.html
  ;用例路径
  testpaths=./testcases
  ;用例分组分类
  markers =
      regression: 回归测试
      smoke: 冒烟测试
  ;日志相关配置
  log_cli = true
  log_cli_level = INFO
  log_cli_date_format = %Y-%m-%d %H:%M:%S
  log_cli_format = %(asctime)s - %(filename)s - %(module)s - %(funcName)s - %(lineno)d - %(levelname)s - %(message)s
  log_file = ../logs/test.log
  测试用例中使用分组markers(一个用例可以添加多个marker):
  import pytest
   
  @pytest.mark.regression
  def test_01():
      print('test01')
   
  @pytest.mark.smoke
  def test_02():
      print('test02')
  @pytest.mark.skip
  def test_03():
      print('test03')
  测试执行
  pytest -m "分组名字"
  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号