• simple-pytest 框架使用指南


    一、框架介绍

    简介

    simple-pytest 框架主要参考了httprunner的yaml数据驱动部分设计思路,是基于 Pytest + Pytest-html+ Log + Yaml + Mysql 实现的简易版接口自动化框架。与httprunner不同的是,httprunner是个封装好的工具包,simple-pytest 是半封装的脚本,目的是让用户自己更容易学习Pytest工具,理解框架设计。

    框架理念:

    1、一个yaml就是一个接口,包含了接口的请求,断言等信息。
    2、脚本执行使用pytest+python代码做逻辑处理,更加方便喜欢写代码的同学
    3、让新手同学更加全面的理解pytest框架
    4、为了
    在学这个框架前,必备的一点常识是:
    1、python基础语法
    2、pytest基础包括用例执行,夹具使用等

    框架地址

    gitee: https://gitee.com/itestxs/simple-pytest

    二、实现功能

    • yaml数据驱动:实现数据驱动隔离
    • 用例标签:在py脚本中可以通过case_tag做用例过滤
    • 全局变量池:实现接口之间的关联取值
    • 多断言:支持==,!=等多种断言,支持jsonpath的取值方式
    • sql数据库断言: 直接在yaml测试用例中写入查询的sql即可断言,无需编写代码
    • 自动生成用例代码: 在yaml文件中填写好测试用例, 可以转换为py脚本。

    三、目录结构

    - config ====>> 项目配置文件redis,mysql等
    - data ====>> 测试数据文件管理
    - logs ====>> 日志记录
    - reports ====>> 结果报告,包括html
    - test_cases ====>> 测试用例 
        ├── confset.py ====>> 测试夹具
    - utils ====>> 各种工具类
        ├── assertion ====>>  断言工具
    - pytest.ini ====>> pytest配置文件
    - conftest.py ====>> 全局夹具配置
    - requirements.txt ====>> 相关依赖包文件
    - run.py ====>> 执行用例入口文件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    四、依赖库

    requests==2.28.1
    jsonpath==0.82
    fastapi==0.88.0
    pymysql==1.0.2
    pyyaml==5.4.1
    pytest==7.4.3
    pytest-html==4.1.1
    py==1.11.0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    五、启动方式

    1、先安装pip install requirements.txt
    2、启用utils下的shopping_mock模块
    3、运行run.py文件,然后,查看report的结果报告即可。

    六、使用教程

    1、快速开始

    1.1、创建用例:

    在data目录下创建yaml文件

    主要的字段格式如下:
    title:接口名字
    base_url:域名地址,不填则默认取得setting的BASE_URL,如果填写了,则直接获取填写的
    path:接口请求地址
    method:请求方法
    request_data:统一的请求参数,比如headers
    cases:测试用例集合
    case_name:测试用例名字,支持多个case_name年编写
    case_tag:支持参数avl、dis、only 不填则为avl。其中avl就是可用的意思,dis不可用,only是代表只有当前用例生效。如果只传入only,则其他用例则不被执行,优先级是only>dis>avl。也可以自定义打tag
    json:接口的请求体,可以直接输入字典格式(自动生成的用例不是字典格式)。请注意yaml的格式
    params:接口的url请求参数。(待补充用例)
    assert:断言,status_code是断言请求状态码。$.data是jsonpath的表达式,目前仅支持改表达式写法。目前支持的断言方式请在assert_type.py里查看包含,大于、不等于、等于一系列判断
    sql:该case关联的sql,可以将该sql用来做前置还是以及后置
    extract_sql:提起该sql的返回内容的某个字段存在变量池中,$.id 也是jsonpath表达式
    assert_sql:sql的断言,用法同assert

    yaml 模板用例如下:

    title: "查询商品"
    base_url: $config{BASE_URL}
    path: /items
    method: GET
    request_data:
      headers:
        Content-Type: application/json
        token: $global{token}
    
    cases:
      - case_name: "搜索-正常"
        # case_tag 支持参数avl、dis、only 不填则为avl,如果只传入only,则所有case 只会返回only的数据,也可以自定义打tag
        case_tag: avl
        assert:
          - eq: [ status_code, 200 ]
          - ne: [ $.data, "" ]
        sql: select * from projectInfo where project="bm-scm"
        extract_sql:
          id: $.id
        assert_sql:
          - eq: [ $.id, 1 ]
      - case_name: "搜索-超出范围"
        case_tag: avl
        params: "page=2&limit=10"
        assert:
          - eq: [ status_code, 200 ]
          - eq: [ $.data, [] ]
    
    • 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
    # login.yaml
    title: "登录"
    path: /login
    method: POST
    request_data:
      headers:
        Content-Type: application/json
    
    cases:
      - case_name: "登录-正常"
        # case_tag 支持参数avl、dis、only 不填则为avl,如果只传入only,则所有case 只会返回only的数据,也可以自定义打tag
        case_tag: avl
        json: {"username": "user1", "password": "password1"}
        extract:
          token: $.token
        assert:
          - eq: [status_code, 200]
          - ne: [$.token, ""]
    
    
      - case_name: "登录-用户名为空"
        case_tag: avl
        json: { "username": "", "password": "password1" }
        assert:
          - eq: [status_code, 401]
          - eq: [$.detail, "Invalid username or password"]
    
    • 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

    1.2、生成py文件

    在utils目录下的yaml_to_py文件main修改,yaml_to_pys批量转换整个data文件夹下的yaml文件,yaml_to_py转换指定的yaml文件,参数,cover代表是否覆盖,传入true,则会覆盖你现有的。

    if __name__ == '__main__':
        yaml_to_pys()
        # yaml_to_py("login.yaml")
    
    • 1
    • 2
    • 3

    case_datas 为自动获取测试用例集,可以通过get_case_data(case_tag=“tag”)中的case_tag去过滤特定标签用例。

    1.3、运行脚本

    1.3.1 单个脚本运行

    每个执行py脚本都可直接右击执行

    1.3.2 全部运行

    点击运行run文件,可以通过testenv 参数指定获取哪个环境的配置。

    1.4 报告查看

    如果是单个配置,则直接在当前test_cases目录下就可以看到,如果是run脚本执行,则报告统一放在reports
    目前的报告格式是pytest-html。如果要用allure,则可以自己修改使用。

    2、功能介绍

    2.1、单个接口http请求与断言

        response = HttpRequest.simple_request(case_data)
        Assert(response, case_data.get("assert")).assert_util
    
    • 1
    • 2
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    import pytest
    
    from utils.assertion.assert_util import Assert
    from utils.http_request import HttpRequest
    from utils.read_file_data import ReadFileData
    
    
    class TestLogin():
        case_datas = ReadFileData("login.yaml").get_case_data()  # get_case_data("tag") 自定义tag输入
    
        @pytest.mark.parametrize('case_data', case_datas, ids=generate_ids(case_datas))
        def test_login(self, case_data):
            response = HttpRequest.simple_request(case_data)
            Assert(response, case_data.get("assert")).assert_util
    
    
    if __name__ == '__main__':
        pytest.main(["test_login.py"])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    2.2、长链路业务http请求与断言

    该功能是添加购车然后付款的流程。 彼此之间有接口依赖问题,通常解决依赖问题有两种

    • 第一种:使用框架自带的merge_cases_data函数
      test_data = merge_cases_data(add_carts_data, order_pays_data) # 将多个用例合并。merge_cases_data 是依赖接口合并,有两个默认规则,如果两个接口用例数一样多的,如[x,y],[A,B]那用例合并后结果就是[x,A] ,[y,B],如果两个接口用例数不一样,如[x] [A,B]那结果就是[x,A],[x,B],如[x,y] [A]那结果就是[x,A],[y,A]。
    • 第二种:自己编写代码逻辑。
      每个yaml就是一个接口。获取每个yaml的接口数据,然后获取用例后if else逻辑。如果接口之前有变量依赖,请借助全局变量去取。
    
    import pytest
    
    from utils.assertion.assert_util import Assert
    from utils.http_request import HttpRequest
    from utils.merge_cases import merge_cases_data, generate_ids
    from utils.read_file_data import ReadFileData
    
    
    class TestAddPay():
        add_carts_data = ReadFileData("add_carts.yaml").get_case_data()  # get_case_data("tag") 自定义tag输入
    
        order_pays_data = ReadFileData("order_pays.yaml").get_case_data()
    
        test_data = merge_cases_data(add_carts_data, order_pays_data) # 将多个用例合并
        print("testdata",test_data)
        @pytest.mark.parametrize('add_carts_data,order_pays_data', test_data, ids=generate_ids(test_data,"merge"))
        def test_add_pay(self, add_carts_data, order_pays_data):
            add_carts_response = HttpRequest.simple_request(add_carts_data)
            # print(add_carts_response.json())
            Assert(add_carts_response, add_carts_data.get("assert")).assert_util
    
            order_pays_response = HttpRequest.simple_request(order_pays_data)
            # print(order_pays_response.json())
            Assert(order_pays_response, order_pays_data.get("assert")).assert_util
    
    
    if __name__ == '__main__':
        pytest.main(["test_add_pay.py"])
    
    • 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
    • 29

    2.3、数据库断言

    需要提前在config配置settings的MYSQL_CONFIG参数

    data = SqlRequest.sql_request(case_data)
    Assert(data, case_data.get("assert_sql")).sql_assert_util
    
    • 1
    • 2

    如果要讲数据库字段提取出来,则写在

    GlobalVars.update_global_vars(key=“data”, value=data) # 将参数手动添加到公共变量中

    import json
    
    import pytest
    
    from utils.assertion.assert_util import Assert
    from utils.global_vars import GlobalVars
    from utils.http_request import HttpRequest
    from utils.read_file_data import ReadFileData
    from utils.sql_reqeust import SqlRequest
    
    
    class TestSearch():
       case_datas = ReadFileData("search_items.yaml").get_case_data()  # get_case_data("tag") 自定义tag输入
       print(case_datas)
    
       @pytest.mark.parametrize('case_data', case_datas, ids=generate_ids(case_datas))
       def test_search_items(self, case_data):
           response = HttpRequest.simple_request(case_data)
           print(response.json())
           Assert(response, case_data.get("assert")).assert_util
    
           # demo1-数据库断言写法
           # from utils.mysql_manager import db # 注意一定要在测试用例中引用,要不然会连接不上数据库
           # data = db.select_db('select * from projectInfo where project="bm-scm"')
           # print("data",data)
           # GlobalVars.update_global_vars(key="data", value=data) # 将参数手动添加到公共变量中
           # assert data["id"] == 1
    
           # demo2-数据库断言写法
           data = SqlRequest.sql_request(case_data)
           print("data", data)
           GlobalVars.update_global_vars(key="data", value=data) # 将参数手动添加到公共变量中
           Assert(data, case_data.get("assert_sql")).sql_assert_util
    
    
    if __name__ == '__main__':
       pytest.main(["test_search_items.py"])
    
    • 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
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    2.4、变量设置

    主要的变量有两种,一个是全局变量,主要是接口数据库字段等值的传参使用。一个是配置变量,拿去配置里的信息。

    2.4.1、全局变量

    使用用法:使用$global{}关键字获取

    $global{token}

    以上例子是获取全局变量中token的变量
    注意:全局变量如果命名重复会导致值被替换,请使用不同的变量名。

    2.4.2 系统配置变量

    配置变量获取的是config里的setting值,启动的时候,会自动获取当前环境的配置

    $config{BASE_URL}

    2.5 前后置处理

    目前前后置处理由用户自己处理,较为常用的用法是,使用pytest的夹具功能

    2.6 环境配置切换

    使用testenv参数即可切换生产以及测试环境的配置。默认不填的情况下,使用的是测试环境的配置。配置读取的是settings里的信息

    2.7 文件读取

    read_file_data提供函数,支持读取json、yaml、csv、txt等文件

    2.8 通知

    在config settings下配置project、feishu_key信息,运行run脚本,即可发送飞书通知,注意只有运行run脚本才可以发送飞书通知
    [图片]

  • 相关阅读:
    大话“高可用“-Part2∶高可用的干预阶段(原创,转载请标明出处)
    《乔布斯传》英文原著重点词汇笔记(四)【 chapter two 】
    php对接飞书机器人
    netcore webapi action 同时支持 get 和 post 请求
    Spring Security OAuth 笔记
    微信小程序快速入门01(含案例)
    基于SSM实现高校后勤报修系统
    分布式存储系统之Ceph集群存储池操作
    FLIP动画做拖拽排序效果
    HTML做一个简单漂亮的宠物网页(纯html代码)
  • 原文地址:https://blog.csdn.net/LANNY8588/article/details/136256793