Metadata-Version: 2.1
Name: pytest-yaml-yoyo
Version: 1.2.5
Summary: http/https API run by yaml
Home-page: https://github.com/yoyoketang/pytest-yaml-yoyo
Author: 上海-悠悠
Author-email: 283340479@qq.com
License: proprietary
Keywords: pytest,py.test,pytest-yaml,pytest-yaml-yoyo
Classifier: Framework :: Pytest
Classifier: Programming Language :: Python
Classifier: Topic :: Software Development :: Testing
Classifier: Programming Language :: Python :: 3.8
Requires-Python: >=3.8

pypi_seed
=========
基于 httprunner 框架的用例结构，我自己开发了一个pytest + yaml 的框架，那么是不是重复造轮子呢？
不可否认 httprunner 框架设计非常优秀，但是也有缺点，httprunner3.x 的版本虽然也是基于 pytest 框架设计，结合 yaml 执行用例，但是会生成一个py文件去执行。
在辅助函数的引用也很局限，只能获取函数的返回值，不能在 yaml 中对返回值重新二次取值。
那么我的这个框架，就是为了解决这些痛点。。。。

本插件可以实现以下优势：

-  1、基于 pytest 框架安装插件即可使用，环境非常简单
-  2、只需要写 yaml 文件用例即可运行，使用 pytest 运行的命令
-  3、extract 提取结果支持 jmespath、jsonpath、re 正则提取实现参数关联
-  4、validate 丰富的校验方法
-  5、全局仅登录一次，在用例中自动在请求头部添加 Authentication token认证
-  6、用例参数化 parameters 功能实现
-  7、export 提升变量为 session 会话级别，可以跨 yaml 文件传参
-  8、yaml 中调用 fixture 功能实现
-  9、yaml 中调用辅助函数功能使用
-  10、yaml 中调用 hooks 功能
-  11、用例分层机制：API 和用例层
-  12、支持 logging 日志
-  13、支持 allure 报告
-  14、支持 mysql 数据库增删改查
-  15、支持钉钉/飞书机器人通知测试结果和 allure 报告地址
-  16、支持生成随机测试数据，如字符串，姓名，手机号，邮箱等
-  17、根据 swagger.json 自动生成 yaml 文件接口用例
-  18、支持全局代理配置

联系我们
--------------------------

- 作者-上海悠悠 微信/QQ交流:283340479
- blog地址 https://www.cnblogs.com/yoyoketang/
- 视频教学 https://study.163.com/course/courseMain.htm?courseId=1213419817&share=2&shareId=480000002230338


版本变更记录
--------------------------

v1.0.0
发布的第一个版本（已删除)

v1.0.1  发布时间 2022.11.23
可以安装的第一个版本

- 1.实现基础的 pytest 命令 执行yaml 文件用例功能

v1.0.2 发布时间 2022.11.24

- 1.新增extract 关键字，在接口中提取返回结果
- 2.参数关联，上一个接口的返回值可以作为下个接口的入参

详细功能参阅 extract 关键字文档

v1.0.3 发布时间 2022.11.28

- 1.config 新增 fixtures 关键字，在yaml 用例中传fixture功能和参数化功能
- 2.config 新增 parameters，用例参数化实现

详细功能参阅 parameters参数化 关键字文档

v1.0.4 发布时间 2022.11.30
hooks 钩子功能实现

- 1.request 钩子对请求参数预处理
- 2.response 钩子对返回结果处理

详细功能参阅 hooks 钩子 关键字文档

v1.0.5 发布时间 2022.12.05
用例分层机制

- 1.API 层对接口的描述，可以复用
- 2.Test case 用例层引用API层

v1.0.6 发布时间 2022.12.06

一个yaml 中写多个用例，用例步骤可以不是list 类型

- 1.config 和 teststeps 不是必须了
- 2.可以自定义用例名称，用例可以是一个步骤也可以是多个步骤

v1.0.7 发布时间 2022.12.08

新增日志

- 1.日志默认按日期时间保存到logs目录
- 2.console 日志开启在 pytest.ini 配置，或命令行参数

v1.0.8 发布时间 2022.12.09

结合 allure 生成报告
v1.0.9 发布时间 2022.12.09

全局base_url 配置

- 1.pytest.ini 新增 `base_url` 配置
- 2.命令行新增 `--base-url` 参数

v1.1.0 发布时间 2022.12.13

多环境配置切换

- 1.config.py 实现多环境配置
- 2.支持mysql 数据库操作

v1.1.1 发布时间 2022.12.14

钉钉机器人通知测试结果

- 1.config.py 配置钉钉机器人access_token
- 2.测试结果钉钉群通知
- 3.支持 requests_function 和 requests_module 内置 fixture 切换

v1.1.2 发布时间 2022.12.16

内置方法提供

- 1.提供3个常用的内置函数：current_time， rand_value， rand_str
- 2.一个内置fake对象
- 3.修复yaml文件为空或格式不正确时，执行报错的问题

v1.1.3 发布时间 2022.12.17

- 文件上传multipart/form-data 格式支持

v1.1.4 发布时间 2023.2.13

新增3个关键字

- 1.sleep  添加用例之间的sleep 等待时间
- 2.skip   跳过用例功能
- 3.skipif   条件为真时跳过用例

v1.1.5 发布时间 2023.2.16

支持 2 中方式生成 yaml 用例

- 1.本地 swagger.json 文件
- 2.在线 swagger.json 地址

v1.1.8 发布时间 2023.3.17

int 转 str 类型

v1.1.9 发布时间 2023-03-21

做了以下优化

- 1.validate 校验加了text 关键字获取全部body文本内容
- 2.用例分层 api和 testcase 层 validate 校验优化，解决之前遗留的bug
- 3.validate 校验方式更灵活，支持int类型校验字符长度和包含字符
- 4.log 日志文件优化，只保留最近的5个日志文件

v1.2.0 发布时间 2023-05-08

优化以下问题

- 1.断言的时候 None 和 'None' 可以判断是相等，在yaml中可以写null 或者 None, 不区分类型了
- 2.添加局部变量variables
- 3.优化request 下的hook 功能
- 4.其它细节优化

v1.2.1 发布时间 2023-05-20

优化以下问题

- 1.兼容python3.8, python3.9, python3.10版本
- 2.支持在case 用例中针对单个用例的参数化了
- 3.参数化数据支持读取外部文件，文件格式可以支持：txt/csv/json/yaml
- 4.函数的参数可以引用变量了，如: ${fun("hello ${key}")}
- 5.内置to_json() 函数，字典转 json

v1.2.2 发布

优化以下问题

- 1.解决与 pytest-base-url 不兼容问题
- 2.解决len_eq 断言 list 长度问题

v1.2.3 发布 2023-05-29

优化以下问题

- 1.解决请求钩子函数中传环境配置问题
- 2.新增内置fixture environ 返回当前运行环境对象
- 3.报告总结加skip通过数量

v1.2.4 发布 2023-05-30

优化以下问题

- 1.解决用例全部 skip 报错问题
- 2.解决文件上传参数全部传 files 不生效问题
- 3.数据库配置支持 DB_INFO 参数传字典类型
- 4.jmespath 表达式支持 length 等函数的提取

v1.2.5 发布 2023-06-07

优化以下问题

- 1.优化参数化路径读取，以项目根路径拼接路径

Installation / 安装
--------------------------
最佳环境体验

- Python 3.8, 3.9. 3.10 版本
- Pytest 7.2.0+

pip 安装插件

::

    pip install pytest-yaml-yoyo



Usage / 第一个 hello world
--------------------------

yaml 用例编写规则，跟pytest识别默认规则一样，必须是test 开头的，以`.yml` 结尾的文件才会被识别

新建一个`test_hello.yml`文件

::

    config:
      name: yy

    teststeps:
    -
      name: demo
      print: hello world

用例整体结构延续了 httprunner 框架的用例结果，主要是为了大家快速上手，减少新的规则学习

- config  是必须的里面必须有 name 用例名称，base_url 和 variables 是可选的
- teststeps 用例的步骤，用例步骤是一个array 数组类型，可以有多个步骤

从上面的运行可以看出，request 不是必须的，我们可以直接调用python内置函数print 去打印一些内容了。

一个简单的 http 请求
--------------------------

以`http://www.example.com/` get 请求示例
test_get_demo.yml

::

    config:
      name: get

    teststeps:
    -
      name: get
      request:
        method: GET
        url: http://httpbin.org/get
      validate:
        - eq: [status_code, 200]

命令行输入 pytest 后直接运行

::

    >pytest
    ======================= test session starts =======================
    platform win32 -- Python 3.8.5, pytest-7.2.0, pluggy-1.0.0
    rootdir: D:\demo\yaml_yoyo
    plugins: yaml-yoyo-1.0.1
    collected 2 items

    test_get_demo.yml .                                          [ 50%]
    test_hello.yml .                                             [100%]

    ======================== 2 passed in 0.49s ========================

再来一个post请求
--------------------------

test_post_demo.yml
::

    config:
      name: post示例

    teststeps:
    -
      name: post
      request:
        method: POST
        url: http://httpbin.org/post
        json:
          username: test
          password: "123456"
      validate:
        - eq: [status_code, 200]
        - eq: [headers.Server, gunicorn/19.9.0]
        - eq: [$..username, test]
        - eq: [body.json.username, test]

validate校验
--------------------------

比如返回的response内容

::

    HTTP/1.1 200 OK
    Date: Wed, 23 Nov 2022 06:26:25 GMT
    Content-Type: application/json
    Content-Length: 483
    Connection: keep-alive
    Server: gunicorn/19.9.0
    Access-Control-Allow-Origin: *
    Access-Control-Allow-Credentials: true

    {
      "args": {},
      "data": "{\r\n    \"username\": \"test\",\r\n    \"password\": \"123456\"\r\n}",
      "files": {},
      "form": {},
      "headers": {
        "Content-Length": "55",
        "Content-Type": "application/json",
        "Host": "httpbin.org",
        "User-Agent": "Fiddler",
        "X-Amzn-Trace-Id": "Root=1-637dbd11-7d9943ba1fb93a9331f6cf8d"
      },
      "json": {
        "password": "123456",
        "username": "test"
      },
      "origin": "198.187.30.113",
      "url": "http://httpbin.org/post"
    }

校验方式延续了httprunner的校验语法，可以支持response取值对象：status_code, url, ok, headers, cookies, text, json, encoding
其中返回的是json格式，那么可以支持

- jmespath 取值语法: `body.json.username`
- jsonpath 语法: `$..username`
- re 正则语法

如果返回的不是json格式，那么可以用正则取值

变量的声明与引用
--------------------------

变量的声明，只支持在 config 声明整个yml文件的全局变量（不支持单个step的变量，减少学习成本）
在 httprunner 里面变量引用语法是 `$user`, 引用函数是`${function()}`
我这里统一改成了一个语法变量引用 `${var}` 和 引用函数`${function()}`
（表面上没多大变量，实际上功能强大了很多，使用了强大的 jinja2 模板引擎)

::

    config:
      name: post示例
      variables:
        username: test
        password: "123456"

    teststeps:
    -
      name: post
      request:
        method: POST
        url: http://httpbin.org/post
        json:
          username: ${username}
          password: ${password}
      validate:
        - eq: [status_code, 200]
        - eq: [headers.Server, gunicorn/19.9.0]
        - eq: [$..username, test]
        - eq: [body.json.username, test]

extract 提取接口返回参数关联
--------------------------------

在自动化用例中，我们经常会看到有人提问，上一个接口的返回的结果，如何取出来给到下个接口的入参。
我们用 extract 关键字提取接口的返回结果（需要更新v1.0.2版本）。


举个例子
用个post请求`http://httpbin.org/post`

::

    POST http://httpbin.org/post HTTP/1.1
    User-Agent: Fiddler
    Host: httpbin.org
    Content-Length: 0

    HTTP/1.1 200 OK
    Date: Thu, 24 Nov 2022 06:18:03 GMT
    Content-Type: application/json
    Content-Length: 320
    Connection: keep-alive
    Server: gunicorn/19.9.0
    Access-Control-Allow-Origin: *
    Access-Control-Allow-Credentials: true

    {
      "args": {},
      "data": "",
      "files": {},
      "form": {},
      "headers": {
        "Content-Length": "0",
        "Host": "httpbin.org",
        "User-Agent": "Fiddler",
        "X-Amzn-Trace-Id": "Root=1-637f0c9a-23b419f4180f6b843ba941af"
      },
      "json": null,
      "origin": "66.112.216.24",
      "url": "http://httpbin.org/post"
    }

比如我需要提取返回接口里面的url参数，那么我们用extract 关键字

test_demo.yml 文件示例

::

    config:
      name: post示例

    teststeps:
    -
      name: post
      request:
        method: POST
        url: http://httpbin.org/post
        json:
          username: test
          password: "123456"
      extract:
          url:  body.url
      validate:
        - eq: [status_code, 200]
        - eq: [headers.Server, gunicorn/19.9.0]
        - eq: [$..username, test]
        - eq: [body.json.username, test]

参数关联
--------------------------


上一个接口提取到了url 变量，接下来在下个接口中引用`${url}`

::

    config:
      name: post示例

    teststeps:
    -
      name: post
      request:
        method: POST
        url: http://httpbin.org/post
        json:
          username: test
          password: "123456"
      extract:
          url:  body.url
      validate:
        - eq: [status_code, 200]
        - eq: [headers.Server, gunicorn/19.9.0]
        - eq: [$..username, test]
        - eq: [body.json.username, test]

    -
      name: post
      request:
        method: GET
        url: http://httpbin.org/get
        headers:
          url: ${url}
      validate:
        - eq: [status_code, 200]

于是看到请求报文中引用成功

::

    GET http://httpbin.org/get HTTP/1.1
    Host: httpbin.org
    User-Agent: python-requests/2.28.1
    Accept-Encoding: gzip, deflate, br
    Accept: */*
    Connection: keep-alive
    url: http://httpbin.org/post

extract 提取结果二次取值
--------------------------

我们在前面提到不能在yaml中对返回值重新二次取值。,
这也是一些同学提到的问题，对于提取的结果，我想继续取值，比如他是一个字符串，在python中可以用切片取值
那么，在 yaml 中如何实现？

我重新设计的这个框架中，就可以支持python语法，直接用切片取值

::

    headers:
          url: ${url[:4]}


用例分层
--------------------------

当我们测试流程类的接口，需反复去调用同一个接口，就会想到复用API，在代码里面可以写成函数去调用。
那么在yaml 文件中，我们可以把单个API写到一个yaml 文件，测试用例去调用导入API。

我这里只分2层：API 层 和 Test case 用例层

- API 层: 描述接口request请求，可以带上validate 基本的校验
- Test case 用例层: 用例层多个步骤按顺序引用API

API 层示例
--------------------------
API 层只做接口的描述，一般放到项目根目录api目录下

api/login.yaml 示例

::

    name: post
    request:
        method: POST
        url: http://httpbin.org/post
        json:
            username: ${username}
            password: "123456"
    validate:
        - eq: [status_code, 200]


如果有需要用到变量，比如登录用户名在不同用例中会用到不同的账号，那么可以使用变量 `${username}`
需注意的是，API 层不支持单独运行，因为它只是用例的一个部分，不能当成用例去执行，用例执行需使用 `test_*.yml` 命名

TestCase 层
--------------------------
用例层通过api 关键字导入需要的API，导入的路径是相对路径，需根据项目的根目录去导入。
比如我的项目结构是这样的

::

    ├─api
       └─ login.yml
    ├─testcase
       └─ test_login.yml
    └─conftest.py
    └─pytest.ini


那么不管用例文件`test_*.yml`在哪个目录，都是以项目根目录去导入API 的yaml文件

::

    config:
        name: login case
        base_url: http://127.0.0.1:8000
        variables:
            username: "test123"
            password: "123456"


    teststeps:
    -
        name: step login1
        api: api/login.yml
        extract:
            url:  body.url
        validate:
            - eq: [status_code, 200]
            - eq: [ok, true]
    -
        name: step login2
        api: api/login.yml


运行用例也是在项目根目录去执行 pytest 运行

::

    pytest testcase


重新定义 yaml 用例格式
--------------------------

一个yaml 文件中可以写多个用例，每个用例相当于 pytest 的一个函数，
用例名称最好是test开头，如果不是test开头，也会自动拼接成test开头的

示例

::

    test1:
        name: 用例1
        print: hello 11111

    test2:
        name: 用例2
        print: hello 22222

    test3:
        name: 用例3
        print: hello 3333

为了框架的可扩展性，config 和 teststeps 都不是必须的了，当然以前的格式还是会兼容

::

    config:
        name: demo

    teststeps:
    -
      name: GET请求示例
      request:
        method: GET
        url: http://httpbin.org/get
      validate:
        - eq: [status_code, 200]

    test1:
        name: 用例1
        print: hello 11111

    test2:
        name: 用例2
        print: hello 22222

用例部分支持2种格式，可以是一个键值对格式

::

    test1:
        name: 用例1
        print: hello 11111


也可以是一个list


::

    test1:
     -
        name: 用例1
        print: hello 11111

如果用多个步骤步骤需要执行，那么用例应该是一个list，会按顺序去执行

::

    config:
        name: demo


    test1:
        name: 用例1
        print: hello 11111

    test2:
    -
        name: get
        request:
            method: GET
            url: http://httpbin.org/get
        validate:
          - eq: [status_code, 200]

    -
        name: post
        request:
            method: POST
            url: http://httpbin.org/post
            json:
              username: test
              password: "123456"
        validate:
          - eq: [status_code, 200]

logging 日志
--------------------------

pytest 的日志分2个部分：

- console 控制台输出的日志
- log_file  保存到本地文件的日志

本插件默认情况下会记录运行日志保存在项目根目录logs下，以当前时间保存txt文本日志内容。
日志默认保存info级别。
console 控制台默认不输出日志

开启 console 控制台日志

控制台直接运行 pytest 是不会用日志输出的，因为默认仅输出 warning 以上的级别日志
有3种方式启动 console 日志

方法1：命令行带上`--log-cli-level`参数，设置日志级别

::

  >pytest --log-cli-level=info

方法2： pytest.ini 配置开启日志，并且设置日志级别

::

    [pytest]

    log_cli = true
    log_cli_level = info

方法3： pytest -o方式重写（即覆盖ini文件中的log相关的命令行参数）

::

    pytest -o log_cli=true -o log_cli_level=INFO


即可在控制台看到日志

::

    -------------------------------------------- live log call --------------------------------------------
    2022-12-08 08:30:34 [INFO]: 执行文件-> test_demo.yml
    2022-12-08 08:30:34 [INFO]: base_url-> None
    2022-12-08 08:30:34 [INFO]: variables-> {}
    2022-12-08 08:30:34 [INFO]: 运行 teststeps
    2022-12-08 08:30:34 [INFO]: --------  request info ----------
    POST http://httpbin.org/post
    {
      "method": "POST",
      "url": "http://httpbin.org/post",
      "json": {
        "username": "test",
        "password": "123456"
      }
    }
    2022-12-08 08:30:35 [INFO]: ------  response info  200 OK  0.495961s------


自定义 console 控制台日志

日志的格式和时间格式也可以自定义设置

::

    [pytest]

    log_cli = true
    log_cli_level = info
    log_cli_format = %(asctime)s %(filename)s:%(lineno)s [%(levelname)s]: %(message)s
    log_cli_date_format = %Y-%m-%d %H:%M:%S


自定义保存日志文件

本插件默认情况下会记录运行日志保存在项目根目录logs下，以当前时间保存txt文本日志内容。
日志默认保存info级别。

如果你想改变这些默认的行为，自定义日志文件目录和名称，可以在pytest.ini 配置日志文件
(log_file 相关的结果是保存日志文件到本地)

::

    [pytest]

    log_cli = true
    log_cli_level = info
    log_cli_format = %(asctime)s %(filename)s:%(lineno)s [%(levelname)s]: %(message)s
    log_cli_date_format = %Y-%m-%d %H:%M:%S

    log_file = ./yoyo.log
    log_file_level = debug
    log_file_format = %(asctime)s %(filename)s:%(lineno)s [%(levelname)s]: %(message)s
    log_file_date_format = %Y-%m-%d %H:%M:%S


命令行参数配置

log日志的配置也可以用命令行参数配置(pytest -h可以查看)

::

     --no-print-logs       　　　　　　 disable printing caught logs on failed tests.
     --log-level=LOG_LEVEL     　　　　logging level used by the logging module
     --log-format=LOG_FORMAT　　　　　　log format as used by the logging module.
     --log-date-format=LOG_DATE_FORMAT　　　　　　log date format as used by the logging module.
     --log-cli-level=LOG_CLI_LEVEL　　　　　　　　cli logging level.
     --log-cli-format=LOG_CLI_FORMAT　　　　　　　　log format as used by the logging module.
     --log-cli-date-format=LOG_CLI_DATE_FORMAT　　　　　　log date format as used by the logging module.
     --log-file=LOG_FILE   　　　　　　　　　　　　path to a file when logging will be written to.
     --log-file-level=LOG_FILE_LEVEL　　　　　　log file logging level.
     --log-file-format=LOG_FILE_FORMAT　　　　　　log format as used by the logging module.
     --log-file-date-format=LOG_FILE_DATE_FORMAT　　　　　　log date format as used by the logging module.


还可以使用 `pytest -o` 方式重写（即覆盖 ini 文件中的 log 相关的命令行参数）

::

  pytest pytest  test_log.py -o log_cli=true -o log_cli_level=INFO


allure  报告
-----------------------

本插件是基于pytest框架开发的，所以pytest 的插件都能使用，生成报告可以用到 allure 报告
allure 报告功能在 v1.0.8 版本上实现

allure 命令行工具

- allure 是一个命令行工具，需要去github上下载最新版[https://github.com/allure-framework/allure2/releases](https://github.com/allure-framework/allure2/releases)
- allure  命令行工具是需要依赖jdk 环境，环境内容自己去搭建了

生成 allure 报告

在用例所在的目录执行命令, `--alluredir` 是指定报告生成的目录

::

    pytest --alluredir ./report


打开allure 报告执行命令
::

    allure serve ./report

全局 base_url
---------------------

一个完整的url 地址由环境地址和接口地址拼接而成，环境地址是可变的，可以部署到测试环境，uat联调环境等不同的环境。
不管部署到哪个环境，接口的地址是不可变的，通常需要一个全局base_url 地址做到环境可切换。
pip 安装插件

::

    pip install pytest-yaml-yoyo


base_url 全局配置功能在 v1.0.9 版本上实现

在接口测试中，通常会把环境 base_url 地址独立出来
比如一个完整的请求`http://httpbin.org/get` 那么可以分成环境地址`http://httpbin.org` 和 接口地址 `/get`

在 yaml 用例中，可以把 base_url 单独拿出来放到 config 下

::

    config:
      base_url: http://httpbin.org

    get示例:
      name: get demo
      request:
        method: GET
        url: /get
      validate:
        - eq: [status_code, 200]

    post示例:
      name: get demo
      request:
        method: POST
        url: /post
      validate:
        - eq: [status_code, 200]


全局 base_url 配置

从项目的角度讲，测试项目接口的 base_url 都是一样的，所以我们只需全局设置一个就行了，不需要每个yaml 文件中重复去写。
于是可以在 pytest.ini 里面配置全局base_url

::

    [pytest]

    base_url = http://httpbin.org


那么yaml用例就不需要写 base_url 了，默认会引用 pytest.ini 的全局配置
