• 自动化测试基础——Pytest框架之YAML详解以及Parametrize数据驱动


    一、YAML详解


    YAML是一个可读性高,用来表达数据序列化的格式。YAML是 “YAML Ain’t a Markup Language”(YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言),但为了强调这种语言以数据做为中心,而不是以标记语言为重点,而用反向缩略语重命名。

    YAML它能够和JSON数据相互转化,它本身也是有很多数据类型可以满足我们接口
    的参数类型,扩展名可以是 .yml.yaml

    1.YAML作用

    1. 全局配置文件:基础路径,数据库信息,账号信息,日志格式,报告名称等。
    2. 编写测试用例:接口自动化测试用例

    2.YAML语法结构

    • 1.区分大小写(大小写敏感)

      Name: 张三
      name: 张三
      
      • 1
      • 2
    • 2.可以使用 # 作为注释(YAML仅支持单行注释)

      # 第一行注释
      Name: 张三
      # 第一行注释
      name: 张三
      
      • 1
      • 2
      • 3
      • 4
    • 3.使用缩进表示层级关系

      • 缩进只能使用 空格,不能用 Tab 制表符
      • 缩进的 空格数量 不重要,但是 同一层级的元素左侧必须对齐
      province: "湖南省"
        city1: "永州市"
        city2: "长沙市"
          area1: "雨花区"
          area2: "天心区"
      
      • 1
      • 2
      • 3
      • 4
      • 5
      Three_stage_linkage:
       province:
        city:
         area: "雨花区"
      
      • 1
      • 2
      • 3
      • 4
    • 4.一个文件可以包含多个文件的内容

      • --- 三个破折号表示一份内容的开始
      • ... 三个小数点表示一份内容的结束,但并不是必需的
      ---
      # 第一份内容
      name: first
      ...
      
      ---
      # 第二份内容
      name: second
      ...
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
    • 5.字符串一般默认可以不使用引号,必须时才使用

    3.YAML数据类型

    • 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
    • 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
    • 标量(scalars):单个的、不可再分的值

    3.1.对象

    • 对象键值对使用冒号结构表示 key: value,冒号后面要加一个空格

      例一(单个)

      key: value
      
      • 1

      例二(多层嵌套)

      key:
        child-key1: value1
        child-key2: value2
      
      • 1
      • 2
      • 3

      例三(流式风格语法)

      key: { child1: value1, child2: value2 }
      
      • 1
    • 较为复杂的对象格式,可以使用问号加一个空格代表一个复杂的key,配合一个冒号加一个空格代表一个 value:

      ?
        - complexkey1
        - complexkey2
      :
        - complexvalue1
        - complexvalue2
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

    3.2.数组

    • - 开头的行表示构成一个数组:

      - A
      - B
      - C
      
      • 1
      • 2
      • 3
      -
       - A
       - B
       - C
      
      • 1
      • 2
      • 3
      • 4
    • YAML支持多维数组,可以使用行内表示:

      key: [value1, value2, ...]
      
      • 1
    • 支持多维数组,用缩进表示层级关系

      values:
        -
          - value1
          - value2
        -
          - value3
          - value4
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    • 复合结构:数组和对象可以构成复合结构,例:

      languages:
        - Java
        - PHP
        - Python
      websites:
        YAML: yaml.org
        Python: python.org
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    3.3.标量


    标量:单个的、不可再分的值。属于YAML中最基本的数据类型

    • 字符串
    • 布尔值
    • 整数
    • 浮点数
    • Null
    • 时间
    • 日期
    #字符串
    string:
        - 哈哈
        - 'Hello world'  #可以使用双引号或者单引号包裹特殊字符(当有特殊字符时:双引号不会被转义,其它的都会加一个转义符 \)
        - newline
          newline2    #字符串可以拆成多行,每一行会被转化成一个空格
    #布尔值
    boolean:
        - TRUE  #true,True都可以
        - FALSE  #false,False都可以
    #整数
    int:
        - 123
        - 0b1010_0111_0100_1010_1110    #二进制表示
    #浮点数
    float:
        - 3.14
        - 6.8523015e+5  #可以使用科学计数法
    #Null
    null:
        nodeName: 'node'
        parent: ~  #使用~表示null(null、Null 和 ~ 都可以表示空,不指定值默认也是空)
    #时间
    datetime:
        -  2018-02-17T15:02:31+08:00    #时间使用ISO 8601格式,时间和日期之间使用T连接,最后使用+代表时区
    #日期
    date:
        - 2018-02-17    #日期必须使用ISO 8601格式,即yyyy-MM-dd
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 字符串
      • 多行字符:字符串可以写成多行,从第二行开始,必须有一个单空格缩进。换行符会被转为空格

        str: 这是一段
          多行
          字符串
        
        • 1
        • 2
        • 3
      • 保留换行:使用竖线符 | 来表示该语法,每行的缩进和行尾空白都会被去掉,而额外的缩进会被保留

        lines: |
          我是第一行
          我是第二行
            我是吴彦祖
              我是第四行
          我是第五行
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
      • 折叠换行:使用右尖括号 > 来表示该语法,只有空白行才会被识别为换行,原来的换行符都会被转换成空格

        lines: >
          我是第一行
          我也是第一行
          我仍是第一行
          我依旧是第一行
        
          我是第二行
          这么巧我也是第二行
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8

    4.YAML的引用


    为了避免重复的定义,YAML 提供了由锚点标签 & 和引用标签 * 组成的语法,利用这套语法可以快速引用相同的一些数据。

    • & 锚点和 * 别名,可以用来引用:

      defaults: &defaults
        adapter:  postgres
        host:     localhost
      
      development:
        database: myapp_development
        <<: *defaults
      
      test:
        database: myapp_test
        <<: *defaults
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      相当于:

      defaults:
        adapter:  postgres
        host:     localhost
      
      development:
        database: myapp_development
        adapter:  postgres
        host:     localhost
      
      test:
        database: myapp_test
        adapter:  postgres
        host:     localhost
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
    • & 用来建立锚点(defaults),<< 表示合并到当前数据,* 用来引用锚点

    5.YAML类型转换

    • YAML 支持使用严格类型标签:!!(双感叹号+目标类型)来强制转换类型

      a: !!float '666' # !! 为严格类型标签,字符串转为浮点数
      b: '666' # 其实双引号也算是类型转换符
      c: !!str 666 # 整数转为字符串
      d: !!str 666.66 # 浮点数转为字符串
      e: !!str true # 布尔值转为字符串
      f: !!str yes # 布尔值转为字符串
      g: !!int '666' # 字符串转为整数
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    二、YAML的读写与清空

    • 安装第三方插件:pip install pyyaml

      pip install pyyaml
      
      • 1

    1.YAML的读

    • 方法一:

      import yaml
      
      
      def read_yaml(yaml_path):
          with open(yaml_path, encoding="utf-8") as f:
              result = yaml.safe_load(f)
              return result
      
      
      result = read_yaml("D:\\develop\\PyCharm\\workspace\\api_frame\\testcase\\test_first_yaml.yaml")
      print(result)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    • 方法二:

      import yaml
      
      
      def read_yaml(yaml_path):
          with open(yaml_path, encoding="utf-8") as f:
              result = yaml.load(f, Loader=yaml.FullLoader)
              return result
      
      
      result = read_yaml("D:\\develop\\PyCharm\\workspace\\api_frame\\testcase\\test_first_yaml.yaml")
      print(result)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

    2.YAML的写

    • 方法一:(覆盖写入)

      import yaml
      
      
      def write_yaml(yaml_path, data):
          with open(yaml_path, mode="w", encoding="utf-8") as f:
              result = yaml.dump(data, stream=f, allow_unicode=True)
      
      
      path = "D:\\develop\\PyCharm\\workspace\\api_frame\\testcase\\test_first_yaml.yaml"
      data = {'province': {'city1': '长沙市', 'city2': '永州市'}}
      write_yaml(path, data)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    • 方法二:(覆盖写入)

      import yaml
      
      
      def write_yaml(yaml_path, data):
          with open(yaml_path, mode="w", encoding="utf-8") as f:
              result = yaml.safe_dump(data, stream=f, allow_unicode=True)
      
      
      path = "D:\\develop\\PyCharm\\workspace\\api_frame\\testcase\\test_first_yaml.yaml"
      data = {'province': {'city1': '长沙市', 'city2': '永州市'}}
      write_yaml(path, data)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    • 方法三:(追加写入)

      import yaml
      
      
      def add_to_yaml(yaml_path, data):
          with open(yaml_path, mode="a+", encoding="utf-8") as f:
              result = yaml.safe_dump(data, stream=f, allow_unicode=True)
      
      
      path = "D:\\develop\\PyCharm\\workspace\\api_frame\\testcase\\test_first_yaml.yaml"
      data = {'province': {'city1': '长沙市', 'city2': '永州市'}}
      add_to_yaml(path, data)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

    3.YAML的清空

    • 方法一:

      # 清空yaml文件内容
      def clean_yam(yaml_path):
          with open(yaml_path, mode="w", encoding="utf-8") as f:
              f.truncate()
      
      
      path = "D:\\develop\\PyCharm\\workspace\\api_frame\\testcase\\test_first_yaml.yaml"
      clean_yam(path)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    • 方法二:

      def clean_yam(yaml_path):
          with open(yaml_path, mode="w", encoding="utf-8") as f:
              pass
      
      
      path = "D:\\develop\\PyCharm\\workspace\\api_frame\\testcase\\test_first_yaml.yaml"
      clean_yam(path)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    三、pytest的parametrize简单数据驱动

    • 使用 @pytest.mark.parametrize("参数名", 参数值(可以是list或tuple)) 实现数据驱动

    • 数据驱动

      import pytest
      
      
      class TestFirstClass():
      
          @pytest.mark.parametrize("name,age", [["张三", 18], ["李四", 28], ["王五", 20]])
          def test_query(self, name, age):
              print(name, age)
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

      在这里插入图片描述

    四、pytest的parametrize结合yaml实现数据驱动

    • 使用 @pytest.mark.parametrize("参数名", 参数值(可以是list或tuple)) 实现数据驱动

    • 1.test_first_yaml.yaml文件内容

      -
        feature: 模块名1
        story: 接口名1
        title: 用例标题1
        request:
          method: 请求方式
          url: 请求路径
          headers: 请求头
          data: 请求数据(可以是data,json,file等)
          validate: 断言
      
      -
        feature: 模块名2
        story: 接口名2
        title: 用例标题2
        request:
          method: 请求方式
          url: 请求路径
          headers: 请求头
          data: 请求数据(可以是data,json,file等)
          validate: 断言
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
    • 2.yaml_util.py文件内容

      import yaml
      
      
      class YamlUtil():
          def __init__(self, yaml_path):
              self.yaml_path = yaml_path
      
          def read_yaml(self):
              with open(self.yaml_path, encoding="utf-8") as f:
                  result = yaml.safe_load(f)
                  return result
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    • 3.test_second_file.py文件内容

      import pytest
      
      from commons.yaml_util import YamlUtil
      
      
      class TestFirstClass():
      
          @pytest.mark.parametrize("caseinfo", YamlUtil("./testcase/test_first_yaml.yaml").read_yaml())
          def test_query(self, caseinfo):
              print(caseinfo)
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    • 4.结果

      在这里插入图片描述

    注意:如果实现数据驱动使用allure测试报告定制会导致allure测试报告页面格式丑陋

    五、解决pytest + allure + yaml实现数据驱动生成测试报告及定制导致的页面丑格式陋问题

    1.问题描述

    在这里插入图片描述
    在这里插入图片描述

    2.解决方法

    1. 找到项目下 venv/Lib/site-packages/allure_pytest/listener.py 源码文件,删除如图所示内容保存,重新启动项目查看allure测试报告结果

      在这里插入图片描述

  • 相关阅读:
    Vue/Vuex (mutations) 核心概念 方法说明、辅助函数 mapMutations使用方法
    详解 ElasticSearch 基础教程
    Docker‘s Network
    1.3.19 网络端口地址转换 NAPT 配置
    java计算机毕业设计火车订票管理系统源码+mysql数据库+系统+lw文档+部署
    QQ表情包存储位置解析
    华为云桌面Workspace,让你的办公更加舒适惬意
    基于EditPlus的PL0语言功能扩充
    软件设计模式
    LeetCode39. Combination Sum
  • 原文地址:https://blog.csdn.net/weixin_44904239/article/details/135695159