pytest-yaml-yoyo


Namepytest-yaml-yoyo JSON
Version 1.2.7 PyPI version JSON
download
home_pagehttps://github.com/yoyoketang/pytest-yaml-yoyo
Summaryhttp/https API run by yaml
upload_time2023-06-19 14:01:03
maintainer
docs_urlNone
author上海-悠悠
requires_python>=3.8
licenseproprietary
keywords pytest py.test pytest-yaml pytest-yaml-yoyo
VCS
bugtrack_url
requirements Jinja2 jmespath jsonpath pytest PyYAML requests
Travis-CI No Travis.
coveralls test coverage No coveralls.
            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.优化参数化路径读取,以项目根路径拼接路径

v1.2.6 发布 2023-06-08

优化以下问题

- 1.优化断言方式 len_eq
- 2.模板过滤器 filter 支持
- 3.变量取值优化, 所有的取值,数字类型默认 int
- 4.取值结果数字转字符串,可以用 `${str(取值表达式)}` 或者过滤器方式 `${取值表达式 | str}`

v1.2.7 发布 2023-06-19

- 1.添加 `--start-project` 命令创建项目 demo


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

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

pip 安装插件

::

    pip install pytest-yaml-yoyo


Usage / 快速创建 demo 项目
--------------------------

使用 `--start-project` 命令快速创建 demo 项目

::

    pytest --start-project

执行后会生成如下项目结构

::

    D:\demo\
    ├── case_demo/
    │   ├── test_extract.yml
    │   ├── test_get.yml
    │   ├── test_post.yml
    ├── config.py
    ├── pytest.ini

通过 pytest 命令可以执行用例

::

  pytest


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 的全局配置

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/yoyoketang/pytest-yaml-yoyo",
    "name": "pytest-yaml-yoyo",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "",
    "keywords": "pytest,py.test,pytest-yaml,pytest-yaml-yoyo",
    "author": "\u4e0a\u6d77-\u60a0\u60a0",
    "author_email": "283340479@qq.com",
    "download_url": "https://files.pythonhosted.org/packages/46/7a/b95640b4b312ec6256944f30ecfc474d6c9c2aa005950dc50e6a7f81a05d/pytest-yaml-yoyo-1.2.7.tar.gz",
    "platform": null,
    "description": "pypi_seed\r\n=========\r\n\u57fa\u4e8e httprunner \u6846\u67b6\u7684\u7528\u4f8b\u7ed3\u6784\uff0c\u6211\u81ea\u5df1\u5f00\u53d1\u4e86\u4e00\u4e2apytest + yaml \u7684\u6846\u67b6\uff0c\u90a3\u4e48\u662f\u4e0d\u662f\u91cd\u590d\u9020\u8f6e\u5b50\u5462\uff1f\r\n\u4e0d\u53ef\u5426\u8ba4 httprunner \u6846\u67b6\u8bbe\u8ba1\u975e\u5e38\u4f18\u79c0\uff0c\u4f46\u662f\u4e5f\u6709\u7f3a\u70b9\uff0chttprunner3.x \u7684\u7248\u672c\u867d\u7136\u4e5f\u662f\u57fa\u4e8e pytest \u6846\u67b6\u8bbe\u8ba1\uff0c\u7ed3\u5408 yaml \u6267\u884c\u7528\u4f8b\uff0c\u4f46\u662f\u4f1a\u751f\u6210\u4e00\u4e2apy\u6587\u4ef6\u53bb\u6267\u884c\u3002\r\n\u5728\u8f85\u52a9\u51fd\u6570\u7684\u5f15\u7528\u4e5f\u5f88\u5c40\u9650\uff0c\u53ea\u80fd\u83b7\u53d6\u51fd\u6570\u7684\u8fd4\u56de\u503c\uff0c\u4e0d\u80fd\u5728 yaml \u4e2d\u5bf9\u8fd4\u56de\u503c\u91cd\u65b0\u4e8c\u6b21\u53d6\u503c\u3002\r\n\u90a3\u4e48\u6211\u7684\u8fd9\u4e2a\u6846\u67b6\uff0c\u5c31\u662f\u4e3a\u4e86\u89e3\u51b3\u8fd9\u4e9b\u75db\u70b9\u3002\u3002\u3002\u3002\r\n\r\n\u672c\u63d2\u4ef6\u53ef\u4ee5\u5b9e\u73b0\u4ee5\u4e0b\u4f18\u52bf\uff1a\r\n\r\n-  1\u3001\u57fa\u4e8e pytest \u6846\u67b6\u5b89\u88c5\u63d2\u4ef6\u5373\u53ef\u4f7f\u7528\uff0c\u73af\u5883\u975e\u5e38\u7b80\u5355\r\n-  2\u3001\u53ea\u9700\u8981\u5199 yaml \u6587\u4ef6\u7528\u4f8b\u5373\u53ef\u8fd0\u884c\uff0c\u4f7f\u7528 pytest \u8fd0\u884c\u7684\u547d\u4ee4\r\n-  3\u3001extract \u63d0\u53d6\u7ed3\u679c\u652f\u6301 jmespath\u3001jsonpath\u3001re \u6b63\u5219\u63d0\u53d6\u5b9e\u73b0\u53c2\u6570\u5173\u8054\r\n-  4\u3001validate \u4e30\u5bcc\u7684\u6821\u9a8c\u65b9\u6cd5\r\n-  5\u3001\u5168\u5c40\u4ec5\u767b\u5f55\u4e00\u6b21\uff0c\u5728\u7528\u4f8b\u4e2d\u81ea\u52a8\u5728\u8bf7\u6c42\u5934\u90e8\u6dfb\u52a0 Authentication token\u8ba4\u8bc1\r\n-  6\u3001\u7528\u4f8b\u53c2\u6570\u5316 parameters \u529f\u80fd\u5b9e\u73b0\r\n-  7\u3001export \u63d0\u5347\u53d8\u91cf\u4e3a session \u4f1a\u8bdd\u7ea7\u522b\uff0c\u53ef\u4ee5\u8de8 yaml \u6587\u4ef6\u4f20\u53c2\r\n-  8\u3001yaml \u4e2d\u8c03\u7528 fixture \u529f\u80fd\u5b9e\u73b0\r\n-  9\u3001yaml \u4e2d\u8c03\u7528\u8f85\u52a9\u51fd\u6570\u529f\u80fd\u4f7f\u7528\r\n-  10\u3001yaml \u4e2d\u8c03\u7528 hooks \u529f\u80fd\r\n-  11\u3001\u7528\u4f8b\u5206\u5c42\u673a\u5236\uff1aAPI \u548c\u7528\u4f8b\u5c42\r\n-  12\u3001\u652f\u6301 logging \u65e5\u5fd7\r\n-  13\u3001\u652f\u6301 allure \u62a5\u544a\r\n-  14\u3001\u652f\u6301 mysql \u6570\u636e\u5e93\u589e\u5220\u6539\u67e5\r\n-  15\u3001\u652f\u6301\u9489\u9489/\u98de\u4e66\u673a\u5668\u4eba\u901a\u77e5\u6d4b\u8bd5\u7ed3\u679c\u548c allure \u62a5\u544a\u5730\u5740\r\n-  16\u3001\u652f\u6301\u751f\u6210\u968f\u673a\u6d4b\u8bd5\u6570\u636e\uff0c\u5982\u5b57\u7b26\u4e32\uff0c\u59d3\u540d\uff0c\u624b\u673a\u53f7\uff0c\u90ae\u7bb1\u7b49\r\n-  17\u3001\u6839\u636e swagger.json \u81ea\u52a8\u751f\u6210 yaml \u6587\u4ef6\u63a5\u53e3\u7528\u4f8b\r\n-  18\u3001\u652f\u6301\u5168\u5c40\u4ee3\u7406\u914d\u7f6e\r\n\r\n\u8054\u7cfb\u6211\u4eec\r\n--------------------------\r\n\r\n- \u4f5c\u8005-\u4e0a\u6d77\u60a0\u60a0 \u5fae\u4fe1/QQ\u4ea4\u6d41:283340479\r\n- blog\u5730\u5740 https://www.cnblogs.com/yoyoketang/\r\n- \u89c6\u9891\u6559\u5b66 https://study.163.com/course/courseMain.htm?courseId=1213419817&share=2&shareId=480000002230338\r\n\r\n\r\n\u7248\u672c\u53d8\u66f4\u8bb0\u5f55\r\n--------------------------\r\n\r\nv1.0.0\r\n\u53d1\u5e03\u7684\u7b2c\u4e00\u4e2a\u7248\u672c\uff08\u5df2\u5220\u9664)\r\n\r\nv1.0.1  \u53d1\u5e03\u65f6\u95f4 2022.11.23\r\n\u53ef\u4ee5\u5b89\u88c5\u7684\u7b2c\u4e00\u4e2a\u7248\u672c\r\n\r\n- 1.\u5b9e\u73b0\u57fa\u7840\u7684 pytest \u547d\u4ee4 \u6267\u884cyaml \u6587\u4ef6\u7528\u4f8b\u529f\u80fd\r\n\r\nv1.0.2 \u53d1\u5e03\u65f6\u95f4 2022.11.24\r\n\r\n- 1.\u65b0\u589eextract \u5173\u952e\u5b57\uff0c\u5728\u63a5\u53e3\u4e2d\u63d0\u53d6\u8fd4\u56de\u7ed3\u679c\r\n- 2.\u53c2\u6570\u5173\u8054\uff0c\u4e0a\u4e00\u4e2a\u63a5\u53e3\u7684\u8fd4\u56de\u503c\u53ef\u4ee5\u4f5c\u4e3a\u4e0b\u4e2a\u63a5\u53e3\u7684\u5165\u53c2\r\n\r\n\u8be6\u7ec6\u529f\u80fd\u53c2\u9605 extract \u5173\u952e\u5b57\u6587\u6863\r\n\r\nv1.0.3 \u53d1\u5e03\u65f6\u95f4 2022.11.28\r\n\r\n- 1.config \u65b0\u589e fixtures \u5173\u952e\u5b57\uff0c\u5728yaml \u7528\u4f8b\u4e2d\u4f20fixture\u529f\u80fd\u548c\u53c2\u6570\u5316\u529f\u80fd\r\n- 2.config \u65b0\u589e parameters\uff0c\u7528\u4f8b\u53c2\u6570\u5316\u5b9e\u73b0\r\n\r\n\u8be6\u7ec6\u529f\u80fd\u53c2\u9605 parameters\u53c2\u6570\u5316 \u5173\u952e\u5b57\u6587\u6863\r\n\r\nv1.0.4 \u53d1\u5e03\u65f6\u95f4 2022.11.30\r\nhooks \u94a9\u5b50\u529f\u80fd\u5b9e\u73b0\r\n\r\n- 1.request \u94a9\u5b50\u5bf9\u8bf7\u6c42\u53c2\u6570\u9884\u5904\u7406\r\n- 2.response \u94a9\u5b50\u5bf9\u8fd4\u56de\u7ed3\u679c\u5904\u7406\r\n\r\n\u8be6\u7ec6\u529f\u80fd\u53c2\u9605 hooks \u94a9\u5b50 \u5173\u952e\u5b57\u6587\u6863\r\n\r\nv1.0.5 \u53d1\u5e03\u65f6\u95f4 2022.12.05\r\n\u7528\u4f8b\u5206\u5c42\u673a\u5236\r\n\r\n- 1.API \u5c42\u5bf9\u63a5\u53e3\u7684\u63cf\u8ff0\uff0c\u53ef\u4ee5\u590d\u7528\r\n- 2.Test case \u7528\u4f8b\u5c42\u5f15\u7528API\u5c42\r\n\r\nv1.0.6 \u53d1\u5e03\u65f6\u95f4 2022.12.06\r\n\r\n\u4e00\u4e2ayaml \u4e2d\u5199\u591a\u4e2a\u7528\u4f8b\uff0c\u7528\u4f8b\u6b65\u9aa4\u53ef\u4ee5\u4e0d\u662flist \u7c7b\u578b\r\n\r\n- 1.config \u548c teststeps \u4e0d\u662f\u5fc5\u987b\u4e86\r\n- 2.\u53ef\u4ee5\u81ea\u5b9a\u4e49\u7528\u4f8b\u540d\u79f0\uff0c\u7528\u4f8b\u53ef\u4ee5\u662f\u4e00\u4e2a\u6b65\u9aa4\u4e5f\u53ef\u4ee5\u662f\u591a\u4e2a\u6b65\u9aa4\r\n\r\nv1.0.7 \u53d1\u5e03\u65f6\u95f4 2022.12.08\r\n\r\n\u65b0\u589e\u65e5\u5fd7\r\n\r\n- 1.\u65e5\u5fd7\u9ed8\u8ba4\u6309\u65e5\u671f\u65f6\u95f4\u4fdd\u5b58\u5230logs\u76ee\u5f55\r\n- 2.console \u65e5\u5fd7\u5f00\u542f\u5728 pytest.ini \u914d\u7f6e\uff0c\u6216\u547d\u4ee4\u884c\u53c2\u6570\r\n\r\nv1.0.8 \u53d1\u5e03\u65f6\u95f4 2022.12.09\r\n\r\n\u7ed3\u5408 allure \u751f\u6210\u62a5\u544a\r\nv1.0.9 \u53d1\u5e03\u65f6\u95f4 2022.12.09\r\n\r\n\u5168\u5c40base_url \u914d\u7f6e\r\n\r\n- 1.pytest.ini \u65b0\u589e `base_url` \u914d\u7f6e\r\n- 2.\u547d\u4ee4\u884c\u65b0\u589e `--base-url` \u53c2\u6570\r\n\r\nv1.1.0 \u53d1\u5e03\u65f6\u95f4 2022.12.13\r\n\r\n\u591a\u73af\u5883\u914d\u7f6e\u5207\u6362\r\n\r\n- 1.config.py \u5b9e\u73b0\u591a\u73af\u5883\u914d\u7f6e\r\n- 2.\u652f\u6301mysql \u6570\u636e\u5e93\u64cd\u4f5c\r\n\r\nv1.1.1 \u53d1\u5e03\u65f6\u95f4 2022.12.14\r\n\r\n\u9489\u9489\u673a\u5668\u4eba\u901a\u77e5\u6d4b\u8bd5\u7ed3\u679c\r\n\r\n- 1.config.py \u914d\u7f6e\u9489\u9489\u673a\u5668\u4ebaaccess_token\r\n- 2.\u6d4b\u8bd5\u7ed3\u679c\u9489\u9489\u7fa4\u901a\u77e5\r\n- 3.\u652f\u6301 requests_function \u548c requests_module \u5185\u7f6e fixture \u5207\u6362\r\n\r\nv1.1.2 \u53d1\u5e03\u65f6\u95f4 2022.12.16\r\n\r\n\u5185\u7f6e\u65b9\u6cd5\u63d0\u4f9b\r\n\r\n- 1.\u63d0\u4f9b3\u4e2a\u5e38\u7528\u7684\u5185\u7f6e\u51fd\u6570\uff1acurrent_time\uff0c rand_value\uff0c rand_str\r\n- 2.\u4e00\u4e2a\u5185\u7f6efake\u5bf9\u8c61\r\n- 3.\u4fee\u590dyaml\u6587\u4ef6\u4e3a\u7a7a\u6216\u683c\u5f0f\u4e0d\u6b63\u786e\u65f6\uff0c\u6267\u884c\u62a5\u9519\u7684\u95ee\u9898\r\n\r\nv1.1.3 \u53d1\u5e03\u65f6\u95f4 2022.12.17\r\n\r\n- \u6587\u4ef6\u4e0a\u4f20multipart/form-data \u683c\u5f0f\u652f\u6301\r\n\r\nv1.1.4 \u53d1\u5e03\u65f6\u95f4 2023.2.13\r\n\r\n\u65b0\u589e3\u4e2a\u5173\u952e\u5b57\r\n\r\n- 1.sleep  \u6dfb\u52a0\u7528\u4f8b\u4e4b\u95f4\u7684sleep \u7b49\u5f85\u65f6\u95f4\r\n- 2.skip   \u8df3\u8fc7\u7528\u4f8b\u529f\u80fd\r\n- 3.skipif   \u6761\u4ef6\u4e3a\u771f\u65f6\u8df3\u8fc7\u7528\u4f8b\r\n\r\nv1.1.5 \u53d1\u5e03\u65f6\u95f4 2023.2.16\r\n\r\n\u652f\u6301 2 \u4e2d\u65b9\u5f0f\u751f\u6210 yaml \u7528\u4f8b\r\n\r\n- 1.\u672c\u5730 swagger.json \u6587\u4ef6\r\n- 2.\u5728\u7ebf swagger.json \u5730\u5740\r\n\r\nv1.1.8 \u53d1\u5e03\u65f6\u95f4 2023.3.17\r\n\r\nint \u8f6c str \u7c7b\u578b\r\n\r\nv1.1.9 \u53d1\u5e03\u65f6\u95f4 2023-03-21\r\n\r\n\u505a\u4e86\u4ee5\u4e0b\u4f18\u5316\r\n\r\n- 1.validate \u6821\u9a8c\u52a0\u4e86text \u5173\u952e\u5b57\u83b7\u53d6\u5168\u90e8body\u6587\u672c\u5185\u5bb9\r\n- 2.\u7528\u4f8b\u5206\u5c42 api\u548c testcase \u5c42 validate \u6821\u9a8c\u4f18\u5316\uff0c\u89e3\u51b3\u4e4b\u524d\u9057\u7559\u7684bug\r\n- 3.validate \u6821\u9a8c\u65b9\u5f0f\u66f4\u7075\u6d3b\uff0c\u652f\u6301int\u7c7b\u578b\u6821\u9a8c\u5b57\u7b26\u957f\u5ea6\u548c\u5305\u542b\u5b57\u7b26\r\n- 4.log \u65e5\u5fd7\u6587\u4ef6\u4f18\u5316\uff0c\u53ea\u4fdd\u7559\u6700\u8fd1\u76845\u4e2a\u65e5\u5fd7\u6587\u4ef6\r\n\r\nv1.2.0 \u53d1\u5e03\u65f6\u95f4 2023-05-08\r\n\r\n\u4f18\u5316\u4ee5\u4e0b\u95ee\u9898\r\n\r\n- 1.\u65ad\u8a00\u7684\u65f6\u5019 None \u548c 'None' \u53ef\u4ee5\u5224\u65ad\u662f\u76f8\u7b49\uff0c\u5728yaml\u4e2d\u53ef\u4ee5\u5199null \u6216\u8005 None, \u4e0d\u533a\u5206\u7c7b\u578b\u4e86\r\n- 2.\u6dfb\u52a0\u5c40\u90e8\u53d8\u91cfvariables\r\n- 3.\u4f18\u5316request \u4e0b\u7684hook \u529f\u80fd\r\n- 4.\u5176\u5b83\u7ec6\u8282\u4f18\u5316\r\n\r\nv1.2.1 \u53d1\u5e03\u65f6\u95f4 2023-05-20\r\n\r\n\u4f18\u5316\u4ee5\u4e0b\u95ee\u9898\r\n\r\n- 1.\u517c\u5bb9python3.8, python3.9, python3.10\u7248\u672c\r\n- 2.\u652f\u6301\u5728case \u7528\u4f8b\u4e2d\u9488\u5bf9\u5355\u4e2a\u7528\u4f8b\u7684\u53c2\u6570\u5316\u4e86\r\n- 3.\u53c2\u6570\u5316\u6570\u636e\u652f\u6301\u8bfb\u53d6\u5916\u90e8\u6587\u4ef6\uff0c\u6587\u4ef6\u683c\u5f0f\u53ef\u4ee5\u652f\u6301\uff1atxt/csv/json/yaml\r\n- 4.\u51fd\u6570\u7684\u53c2\u6570\u53ef\u4ee5\u5f15\u7528\u53d8\u91cf\u4e86\uff0c\u5982: ${fun(\"hello ${key}\")}\r\n- 5.\u5185\u7f6eto_json() \u51fd\u6570\uff0c\u5b57\u5178\u8f6c json\r\n\r\nv1.2.2 \u53d1\u5e03\r\n\r\n\u4f18\u5316\u4ee5\u4e0b\u95ee\u9898\r\n\r\n- 1.\u89e3\u51b3\u4e0e pytest-base-url \u4e0d\u517c\u5bb9\u95ee\u9898\r\n- 2.\u89e3\u51b3len_eq \u65ad\u8a00 list \u957f\u5ea6\u95ee\u9898\r\n\r\nv1.2.3 \u53d1\u5e03 2023-05-29\r\n\r\n\u4f18\u5316\u4ee5\u4e0b\u95ee\u9898\r\n\r\n- 1.\u89e3\u51b3\u8bf7\u6c42\u94a9\u5b50\u51fd\u6570\u4e2d\u4f20\u73af\u5883\u914d\u7f6e\u95ee\u9898\r\n- 2.\u65b0\u589e\u5185\u7f6efixture environ \u8fd4\u56de\u5f53\u524d\u8fd0\u884c\u73af\u5883\u5bf9\u8c61\r\n- 3.\u62a5\u544a\u603b\u7ed3\u52a0skip\u901a\u8fc7\u6570\u91cf\r\n\r\nv1.2.4 \u53d1\u5e03 2023-05-30\r\n\r\n\u4f18\u5316\u4ee5\u4e0b\u95ee\u9898\r\n\r\n- 1.\u89e3\u51b3\u7528\u4f8b\u5168\u90e8 skip \u62a5\u9519\u95ee\u9898\r\n- 2.\u89e3\u51b3\u6587\u4ef6\u4e0a\u4f20\u53c2\u6570\u5168\u90e8\u4f20 files \u4e0d\u751f\u6548\u95ee\u9898\r\n- 3.\u6570\u636e\u5e93\u914d\u7f6e\u652f\u6301 DB_INFO \u53c2\u6570\u4f20\u5b57\u5178\u7c7b\u578b\r\n- 4.jmespath \u8868\u8fbe\u5f0f\u652f\u6301 length \u7b49\u51fd\u6570\u7684\u63d0\u53d6\r\n\r\nv1.2.5 \u53d1\u5e03 2023-06-07\r\n\r\n\u4f18\u5316\u4ee5\u4e0b\u95ee\u9898\r\n\r\n- 1.\u4f18\u5316\u53c2\u6570\u5316\u8def\u5f84\u8bfb\u53d6\uff0c\u4ee5\u9879\u76ee\u6839\u8def\u5f84\u62fc\u63a5\u8def\u5f84\r\n\r\nv1.2.6 \u53d1\u5e03 2023-06-08\r\n\r\n\u4f18\u5316\u4ee5\u4e0b\u95ee\u9898\r\n\r\n- 1.\u4f18\u5316\u65ad\u8a00\u65b9\u5f0f len_eq\r\n- 2.\u6a21\u677f\u8fc7\u6ee4\u5668 filter \u652f\u6301\r\n- 3.\u53d8\u91cf\u53d6\u503c\u4f18\u5316, \u6240\u6709\u7684\u53d6\u503c\uff0c\u6570\u5b57\u7c7b\u578b\u9ed8\u8ba4 int\r\n- 4.\u53d6\u503c\u7ed3\u679c\u6570\u5b57\u8f6c\u5b57\u7b26\u4e32\uff0c\u53ef\u4ee5\u7528 `${str(\u53d6\u503c\u8868\u8fbe\u5f0f)}` \u6216\u8005\u8fc7\u6ee4\u5668\u65b9\u5f0f `${\u53d6\u503c\u8868\u8fbe\u5f0f | str}`\r\n\r\nv1.2.7 \u53d1\u5e03 2023-06-19\r\n\r\n- 1.\u6dfb\u52a0 `--start-project` \u547d\u4ee4\u521b\u5efa\u9879\u76ee demo\r\n\r\n\r\nInstallation / \u5b89\u88c5\r\n--------------------------\r\n\u6700\u4f73\u73af\u5883\u4f53\u9a8c\r\n\r\n- Python 3.8, 3.9. 3.10 \u7248\u672c\r\n- Pytest 7.2.0+\r\n\r\npip \u5b89\u88c5\u63d2\u4ef6\r\n\r\n::\r\n\r\n    pip install pytest-yaml-yoyo\r\n\r\n\r\nUsage / \u5feb\u901f\u521b\u5efa demo \u9879\u76ee\r\n--------------------------\r\n\r\n\u4f7f\u7528 `--start-project` \u547d\u4ee4\u5feb\u901f\u521b\u5efa demo \u9879\u76ee\r\n\r\n::\r\n\r\n    pytest --start-project\r\n\r\n\u6267\u884c\u540e\u4f1a\u751f\u6210\u5982\u4e0b\u9879\u76ee\u7ed3\u6784\r\n\r\n::\r\n\r\n    D:\\demo\\\r\n    \u251c\u2500\u2500 case_demo/\r\n    \u2502   \u251c\u2500\u2500 test_extract.yml\r\n    \u2502   \u251c\u2500\u2500 test_get.yml\r\n    \u2502   \u251c\u2500\u2500 test_post.yml\r\n    \u251c\u2500\u2500 config.py\r\n    \u251c\u2500\u2500 pytest.ini\r\n\r\n\u901a\u8fc7 pytest \u547d\u4ee4\u53ef\u4ee5\u6267\u884c\u7528\u4f8b\r\n\r\n::\r\n\r\n  pytest\r\n\r\n\r\nUsage / \u7b2c\u4e00\u4e2a hello world\r\n--------------------------\r\n\r\nyaml \u7528\u4f8b\u7f16\u5199\u89c4\u5219\uff0c\u8ddf pytest \u8bc6\u522b\u9ed8\u8ba4\u89c4\u5219\u4e00\u6837\uff0c\u5fc5\u987b\u662f test \u5f00\u5934\u7684\uff0c\u4ee5`.yml` \u7ed3\u5c3e\u7684\u6587\u4ef6\u624d\u4f1a\u88ab\u8bc6\u522b\r\n\r\n\u65b0\u5efa\u4e00\u4e2a`test_hello.yml`\u6587\u4ef6\r\n\r\n::\r\n\r\n    config:\r\n      name: yy\r\n\r\n    teststeps:\r\n    -\r\n      name: demo\r\n      print: hello world\r\n\r\n\u7528\u4f8b\u6574\u4f53\u7ed3\u6784\u5ef6\u7eed\u4e86 httprunner \u6846\u67b6\u7684\u7528\u4f8b\u7ed3\u679c\uff0c\u4e3b\u8981\u662f\u4e3a\u4e86\u5927\u5bb6\u5feb\u901f\u4e0a\u624b\uff0c\u51cf\u5c11\u65b0\u7684\u89c4\u5219\u5b66\u4e60\r\n\r\n- config  \u662f\u5fc5\u987b\u7684\u91cc\u9762\u5fc5\u987b\u6709 name \u7528\u4f8b\u540d\u79f0\uff0cbase_url \u548c variables \u662f\u53ef\u9009\u7684\r\n- teststeps \u7528\u4f8b\u7684\u6b65\u9aa4\uff0c\u7528\u4f8b\u6b65\u9aa4\u662f\u4e00\u4e2aarray \u6570\u7ec4\u7c7b\u578b\uff0c\u53ef\u4ee5\u6709\u591a\u4e2a\u6b65\u9aa4\r\n\r\n\u4ece\u4e0a\u9762\u7684\u8fd0\u884c\u53ef\u4ee5\u770b\u51fa\uff0crequest \u4e0d\u662f\u5fc5\u987b\u7684\uff0c\u6211\u4eec\u53ef\u4ee5\u76f4\u63a5\u8c03\u7528python\u5185\u7f6e\u51fd\u6570print \u53bb\u6253\u5370\u4e00\u4e9b\u5185\u5bb9\u4e86\u3002\r\n\r\n\u4e00\u4e2a\u7b80\u5355\u7684 http \u8bf7\u6c42\r\n--------------------------\r\n\r\n\u4ee5`http://www.example.com/` get \u8bf7\u6c42\u793a\u4f8b\r\ntest_get_demo.yml\r\n\r\n::\r\n\r\n    config:\r\n      name: get\r\n\r\n    teststeps:\r\n    -\r\n      name: get\r\n      request:\r\n        method: GET\r\n        url: http://httpbin.org/get\r\n      validate:\r\n        - eq: [status_code, 200]\r\n\r\n\u547d\u4ee4\u884c\u8f93\u5165 pytest \u540e\u76f4\u63a5\u8fd0\u884c\r\n\r\n::\r\n\r\n    >pytest\r\n    ======================= test session starts =======================\r\n    platform win32 -- Python 3.8.5, pytest-7.2.0, pluggy-1.0.0\r\n    rootdir: D:\\demo\\yaml_yoyo\r\n    plugins: yaml-yoyo-1.0.1\r\n    collected 2 items\r\n\r\n    test_get_demo.yml .                                          [ 50%]\r\n    test_hello.yml .                                             [100%]\r\n\r\n    ======================== 2 passed in 0.49s ========================\r\n\r\n\u518d\u6765\u4e00\u4e2apost\u8bf7\u6c42\r\n--------------------------\r\n\r\ntest_post_demo.yml\r\n::\r\n\r\n    config:\r\n      name: post\u793a\u4f8b\r\n\r\n    teststeps:\r\n    -\r\n      name: post\r\n      request:\r\n        method: POST\r\n        url: http://httpbin.org/post\r\n        json:\r\n          username: test\r\n          password: \"123456\"\r\n      validate:\r\n        - eq: [status_code, 200]\r\n        - eq: [headers.Server, gunicorn/19.9.0]\r\n        - eq: [$..username, test]\r\n        - eq: [body.json.username, test]\r\n\r\nvalidate\u6821\u9a8c\r\n--------------------------\r\n\r\n\u6bd4\u5982\u8fd4\u56de\u7684response\u5185\u5bb9\r\n\r\n::\r\n\r\n    HTTP/1.1 200 OK\r\n    Date: Wed, 23 Nov 2022 06:26:25 GMT\r\n    Content-Type: application/json\r\n    Content-Length: 483\r\n    Connection: keep-alive\r\n    Server: gunicorn/19.9.0\r\n    Access-Control-Allow-Origin: *\r\n    Access-Control-Allow-Credentials: true\r\n\r\n    {\r\n      \"args\": {},\r\n      \"data\": \"{\\r\\n    \\\"username\\\": \\\"test\\\",\\r\\n    \\\"password\\\": \\\"123456\\\"\\r\\n}\",\r\n      \"files\": {},\r\n      \"form\": {},\r\n      \"headers\": {\r\n        \"Content-Length\": \"55\",\r\n        \"Content-Type\": \"application/json\",\r\n        \"Host\": \"httpbin.org\",\r\n        \"User-Agent\": \"Fiddler\",\r\n        \"X-Amzn-Trace-Id\": \"Root=1-637dbd11-7d9943ba1fb93a9331f6cf8d\"\r\n      },\r\n      \"json\": {\r\n        \"password\": \"123456\",\r\n        \"username\": \"test\"\r\n      },\r\n      \"origin\": \"198.187.30.113\",\r\n      \"url\": \"http://httpbin.org/post\"\r\n    }\r\n\r\n\u6821\u9a8c\u65b9\u5f0f\u5ef6\u7eed\u4e86httprunner\u7684\u6821\u9a8c\u8bed\u6cd5\uff0c\u53ef\u4ee5\u652f\u6301response\u53d6\u503c\u5bf9\u8c61\uff1astatus_code, url, ok, headers, cookies, text, json, encoding\r\n\u5176\u4e2d\u8fd4\u56de\u7684\u662fjson\u683c\u5f0f\uff0c\u90a3\u4e48\u53ef\u4ee5\u652f\u6301\r\n\r\n- jmespath \u53d6\u503c\u8bed\u6cd5: `body.json.username`\r\n- jsonpath \u8bed\u6cd5: `$..username`\r\n- re \u6b63\u5219\u8bed\u6cd5\r\n\r\n\u5982\u679c\u8fd4\u56de\u7684\u4e0d\u662fjson\u683c\u5f0f\uff0c\u90a3\u4e48\u53ef\u4ee5\u7528\u6b63\u5219\u53d6\u503c\r\n\r\n\u53d8\u91cf\u7684\u58f0\u660e\u4e0e\u5f15\u7528\r\n--------------------------\r\n\r\n\u53d8\u91cf\u7684\u58f0\u660e\uff0c\u53ea\u652f\u6301\u5728 config \u58f0\u660e\u6574\u4e2ayml\u6587\u4ef6\u7684\u5168\u5c40\u53d8\u91cf\uff08\u4e0d\u652f\u6301\u5355\u4e2astep\u7684\u53d8\u91cf\uff0c\u51cf\u5c11\u5b66\u4e60\u6210\u672c\uff09\r\n\u5728 httprunner \u91cc\u9762\u53d8\u91cf\u5f15\u7528\u8bed\u6cd5\u662f `$user`, \u5f15\u7528\u51fd\u6570\u662f`${function()}`\r\n\u6211\u8fd9\u91cc\u7edf\u4e00\u6539\u6210\u4e86\u4e00\u4e2a\u8bed\u6cd5\u53d8\u91cf\u5f15\u7528 `${var}` \u548c \u5f15\u7528\u51fd\u6570`${function()}`\r\n\uff08\u8868\u9762\u4e0a\u6ca1\u591a\u5927\u53d8\u91cf\uff0c\u5b9e\u9645\u4e0a\u529f\u80fd\u5f3a\u5927\u4e86\u5f88\u591a\uff0c\u4f7f\u7528\u4e86\u5f3a\u5927\u7684 jinja2 \u6a21\u677f\u5f15\u64ce)\r\n\r\n::\r\n\r\n    config:\r\n      name: post\u793a\u4f8b\r\n      variables:\r\n        username: test\r\n        password: \"123456\"\r\n\r\n    teststeps:\r\n    -\r\n      name: post\r\n      request:\r\n        method: POST\r\n        url: http://httpbin.org/post\r\n        json:\r\n          username: ${username}\r\n          password: ${password}\r\n      validate:\r\n        - eq: [status_code, 200]\r\n        - eq: [headers.Server, gunicorn/19.9.0]\r\n        - eq: [$..username, test]\r\n        - eq: [body.json.username, test]\r\n\r\nextract \u63d0\u53d6\u63a5\u53e3\u8fd4\u56de\u53c2\u6570\u5173\u8054\r\n--------------------------------\r\n\r\n\u5728\u81ea\u52a8\u5316\u7528\u4f8b\u4e2d\uff0c\u6211\u4eec\u7ecf\u5e38\u4f1a\u770b\u5230\u6709\u4eba\u63d0\u95ee\uff0c\u4e0a\u4e00\u4e2a\u63a5\u53e3\u7684\u8fd4\u56de\u7684\u7ed3\u679c\uff0c\u5982\u4f55\u53d6\u51fa\u6765\u7ed9\u5230\u4e0b\u4e2a\u63a5\u53e3\u7684\u5165\u53c2\u3002\r\n\u6211\u4eec\u7528 extract \u5173\u952e\u5b57\u63d0\u53d6\u63a5\u53e3\u7684\u8fd4\u56de\u7ed3\u679c\uff08\u9700\u8981\u66f4\u65b0v1.0.2\u7248\u672c\uff09\u3002\r\n\r\n\r\n\u4e3e\u4e2a\u4f8b\u5b50\r\n\u7528\u4e2apost\u8bf7\u6c42`http://httpbin.org/post`\r\n\r\n::\r\n\r\n    POST http://httpbin.org/post HTTP/1.1\r\n    User-Agent: Fiddler\r\n    Host: httpbin.org\r\n    Content-Length: 0\r\n\r\n    HTTP/1.1 200 OK\r\n    Date: Thu, 24 Nov 2022 06:18:03 GMT\r\n    Content-Type: application/json\r\n    Content-Length: 320\r\n    Connection: keep-alive\r\n    Server: gunicorn/19.9.0\r\n    Access-Control-Allow-Origin: *\r\n    Access-Control-Allow-Credentials: true\r\n\r\n    {\r\n      \"args\": {},\r\n      \"data\": \"\",\r\n      \"files\": {},\r\n      \"form\": {},\r\n      \"headers\": {\r\n        \"Content-Length\": \"0\",\r\n        \"Host\": \"httpbin.org\",\r\n        \"User-Agent\": \"Fiddler\",\r\n        \"X-Amzn-Trace-Id\": \"Root=1-637f0c9a-23b419f4180f6b843ba941af\"\r\n      },\r\n      \"json\": null,\r\n      \"origin\": \"66.112.216.24\",\r\n      \"url\": \"http://httpbin.org/post\"\r\n    }\r\n\r\n\u6bd4\u5982\u6211\u9700\u8981\u63d0\u53d6\u8fd4\u56de\u63a5\u53e3\u91cc\u9762\u7684url\u53c2\u6570\uff0c\u90a3\u4e48\u6211\u4eec\u7528extract \u5173\u952e\u5b57\r\n\r\ntest_demo.yml \u6587\u4ef6\u793a\u4f8b\r\n\r\n::\r\n\r\n    config:\r\n      name: post\u793a\u4f8b\r\n\r\n    teststeps:\r\n    -\r\n      name: post\r\n      request:\r\n        method: POST\r\n        url: http://httpbin.org/post\r\n        json:\r\n          username: test\r\n          password: \"123456\"\r\n      extract:\r\n          url:  body.url\r\n      validate:\r\n        - eq: [status_code, 200]\r\n        - eq: [headers.Server, gunicorn/19.9.0]\r\n        - eq: [$..username, test]\r\n        - eq: [body.json.username, test]\r\n\r\n\u53c2\u6570\u5173\u8054\r\n--------------------------\r\n\r\n\r\n\u4e0a\u4e00\u4e2a\u63a5\u53e3\u63d0\u53d6\u5230\u4e86url \u53d8\u91cf\uff0c\u63a5\u4e0b\u6765\u5728\u4e0b\u4e2a\u63a5\u53e3\u4e2d\u5f15\u7528`${url}`\r\n\r\n::\r\n\r\n    config:\r\n      name: post\u793a\u4f8b\r\n\r\n    teststeps:\r\n    -\r\n      name: post\r\n      request:\r\n        method: POST\r\n        url: http://httpbin.org/post\r\n        json:\r\n          username: test\r\n          password: \"123456\"\r\n      extract:\r\n          url:  body.url\r\n      validate:\r\n        - eq: [status_code, 200]\r\n        - eq: [headers.Server, gunicorn/19.9.0]\r\n        - eq: [$..username, test]\r\n        - eq: [body.json.username, test]\r\n\r\n    -\r\n      name: post\r\n      request:\r\n        method: GET\r\n        url: http://httpbin.org/get\r\n        headers:\r\n          url: ${url}\r\n      validate:\r\n        - eq: [status_code, 200]\r\n\r\n\u4e8e\u662f\u770b\u5230\u8bf7\u6c42\u62a5\u6587\u4e2d\u5f15\u7528\u6210\u529f\r\n\r\n::\r\n\r\n    GET http://httpbin.org/get HTTP/1.1\r\n    Host: httpbin.org\r\n    User-Agent: python-requests/2.28.1\r\n    Accept-Encoding: gzip, deflate, br\r\n    Accept: */*\r\n    Connection: keep-alive\r\n    url: http://httpbin.org/post\r\n\r\nextract \u63d0\u53d6\u7ed3\u679c\u4e8c\u6b21\u53d6\u503c\r\n--------------------------\r\n\r\n\u6211\u4eec\u5728\u524d\u9762\u63d0\u5230\u4e0d\u80fd\u5728yaml\u4e2d\u5bf9\u8fd4\u56de\u503c\u91cd\u65b0\u4e8c\u6b21\u53d6\u503c\u3002,\r\n\u8fd9\u4e5f\u662f\u4e00\u4e9b\u540c\u5b66\u63d0\u5230\u7684\u95ee\u9898\uff0c\u5bf9\u4e8e\u63d0\u53d6\u7684\u7ed3\u679c\uff0c\u6211\u60f3\u7ee7\u7eed\u53d6\u503c\uff0c\u6bd4\u5982\u4ed6\u662f\u4e00\u4e2a\u5b57\u7b26\u4e32\uff0c\u5728python\u4e2d\u53ef\u4ee5\u7528\u5207\u7247\u53d6\u503c\r\n\u90a3\u4e48\uff0c\u5728 yaml \u4e2d\u5982\u4f55\u5b9e\u73b0\uff1f\r\n\r\n\u6211\u91cd\u65b0\u8bbe\u8ba1\u7684\u8fd9\u4e2a\u6846\u67b6\u4e2d\uff0c\u5c31\u53ef\u4ee5\u652f\u6301python\u8bed\u6cd5\uff0c\u76f4\u63a5\u7528\u5207\u7247\u53d6\u503c\r\n\r\n::\r\n\r\n    headers:\r\n          url: ${url[:4]}\r\n\r\n\r\n\u7528\u4f8b\u5206\u5c42\r\n--------------------------\r\n\r\n\u5f53\u6211\u4eec\u6d4b\u8bd5\u6d41\u7a0b\u7c7b\u7684\u63a5\u53e3\uff0c\u9700\u53cd\u590d\u53bb\u8c03\u7528\u540c\u4e00\u4e2a\u63a5\u53e3\uff0c\u5c31\u4f1a\u60f3\u5230\u590d\u7528API\uff0c\u5728\u4ee3\u7801\u91cc\u9762\u53ef\u4ee5\u5199\u6210\u51fd\u6570\u53bb\u8c03\u7528\u3002\r\n\u90a3\u4e48\u5728yaml \u6587\u4ef6\u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u628a\u5355\u4e2aAPI\u5199\u5230\u4e00\u4e2ayaml \u6587\u4ef6\uff0c\u6d4b\u8bd5\u7528\u4f8b\u53bb\u8c03\u7528\u5bfc\u5165API\u3002\r\n\r\n\u6211\u8fd9\u91cc\u53ea\u52062\u5c42\uff1aAPI \u5c42 \u548c Test case \u7528\u4f8b\u5c42\r\n\r\n- API \u5c42: \u63cf\u8ff0\u63a5\u53e3request\u8bf7\u6c42\uff0c\u53ef\u4ee5\u5e26\u4e0avalidate \u57fa\u672c\u7684\u6821\u9a8c\r\n- Test case \u7528\u4f8b\u5c42: \u7528\u4f8b\u5c42\u591a\u4e2a\u6b65\u9aa4\u6309\u987a\u5e8f\u5f15\u7528API\r\n\r\nAPI \u5c42\u793a\u4f8b\r\n--------------------------\r\nAPI \u5c42\u53ea\u505a\u63a5\u53e3\u7684\u63cf\u8ff0\uff0c\u4e00\u822c\u653e\u5230\u9879\u76ee\u6839\u76ee\u5f55api\u76ee\u5f55\u4e0b\r\n\r\napi/login.yaml \u793a\u4f8b\r\n\r\n::\r\n\r\n    name: post\r\n    request:\r\n        method: POST\r\n        url: http://httpbin.org/post\r\n        json:\r\n            username: ${username}\r\n            password: \"123456\"\r\n    validate:\r\n        - eq: [status_code, 200]\r\n\r\n\r\n\u5982\u679c\u6709\u9700\u8981\u7528\u5230\u53d8\u91cf\uff0c\u6bd4\u5982\u767b\u5f55\u7528\u6237\u540d\u5728\u4e0d\u540c\u7528\u4f8b\u4e2d\u4f1a\u7528\u5230\u4e0d\u540c\u7684\u8d26\u53f7\uff0c\u90a3\u4e48\u53ef\u4ee5\u4f7f\u7528\u53d8\u91cf `${username}`\r\n\u9700\u6ce8\u610f\u7684\u662f\uff0cAPI \u5c42\u4e0d\u652f\u6301\u5355\u72ec\u8fd0\u884c\uff0c\u56e0\u4e3a\u5b83\u53ea\u662f\u7528\u4f8b\u7684\u4e00\u4e2a\u90e8\u5206\uff0c\u4e0d\u80fd\u5f53\u6210\u7528\u4f8b\u53bb\u6267\u884c\uff0c\u7528\u4f8b\u6267\u884c\u9700\u4f7f\u7528 `test_*.yml` \u547d\u540d\r\n\r\nTestCase \u5c42\r\n--------------------------\r\n\u7528\u4f8b\u5c42\u901a\u8fc7api \u5173\u952e\u5b57\u5bfc\u5165\u9700\u8981\u7684API\uff0c\u5bfc\u5165\u7684\u8def\u5f84\u662f\u76f8\u5bf9\u8def\u5f84\uff0c\u9700\u6839\u636e\u9879\u76ee\u7684\u6839\u76ee\u5f55\u53bb\u5bfc\u5165\u3002\r\n\u6bd4\u5982\u6211\u7684\u9879\u76ee\u7ed3\u6784\u662f\u8fd9\u6837\u7684\r\n\r\n::\r\n\r\n    \u251c\u2500api\r\n       \u2514\u2500 login.yml\r\n    \u251c\u2500testcase\r\n       \u2514\u2500 test_login.yml\r\n    \u2514\u2500conftest.py\r\n    \u2514\u2500pytest.ini\r\n\r\n\r\n\u90a3\u4e48\u4e0d\u7ba1\u7528\u4f8b\u6587\u4ef6`test_*.yml`\u5728\u54ea\u4e2a\u76ee\u5f55\uff0c\u90fd\u662f\u4ee5\u9879\u76ee\u6839\u76ee\u5f55\u53bb\u5bfc\u5165API \u7684yaml\u6587\u4ef6\r\n\r\n::\r\n\r\n    config:\r\n        name: login case\r\n        base_url: http://127.0.0.1:8000\r\n        variables:\r\n            username: \"test123\"\r\n            password: \"123456\"\r\n\r\n\r\n    teststeps:\r\n    -\r\n        name: step login1\r\n        api: api/login.yml\r\n        extract:\r\n            url:  body.url\r\n        validate:\r\n            - eq: [status_code, 200]\r\n            - eq: [ok, true]\r\n    -\r\n        name: step login2\r\n        api: api/login.yml\r\n\r\n\r\n\u8fd0\u884c\u7528\u4f8b\u4e5f\u662f\u5728\u9879\u76ee\u6839\u76ee\u5f55\u53bb\u6267\u884c pytest \u8fd0\u884c\r\n\r\n::\r\n\r\n    pytest testcase\r\n\r\n\r\n\u91cd\u65b0\u5b9a\u4e49 yaml \u7528\u4f8b\u683c\u5f0f\r\n--------------------------\r\n\r\n\u4e00\u4e2ayaml \u6587\u4ef6\u4e2d\u53ef\u4ee5\u5199\u591a\u4e2a\u7528\u4f8b\uff0c\u6bcf\u4e2a\u7528\u4f8b\u76f8\u5f53\u4e8e pytest \u7684\u4e00\u4e2a\u51fd\u6570\uff0c\r\n\u7528\u4f8b\u540d\u79f0\u6700\u597d\u662ftest\u5f00\u5934\uff0c\u5982\u679c\u4e0d\u662ftest\u5f00\u5934\uff0c\u4e5f\u4f1a\u81ea\u52a8\u62fc\u63a5\u6210test\u5f00\u5934\u7684\r\n\r\n\u793a\u4f8b\r\n\r\n::\r\n\r\n    test1:\r\n        name: \u7528\u4f8b1\r\n        print: hello 11111\r\n\r\n    test2:\r\n        name: \u7528\u4f8b2\r\n        print: hello 22222\r\n\r\n    test3:\r\n        name: \u7528\u4f8b3\r\n        print: hello 3333\r\n\r\n\u4e3a\u4e86\u6846\u67b6\u7684\u53ef\u6269\u5c55\u6027\uff0cconfig \u548c teststeps \u90fd\u4e0d\u662f\u5fc5\u987b\u7684\u4e86\uff0c\u5f53\u7136\u4ee5\u524d\u7684\u683c\u5f0f\u8fd8\u662f\u4f1a\u517c\u5bb9\r\n\r\n::\r\n\r\n    config:\r\n        name: demo\r\n\r\n    teststeps:\r\n    -\r\n      name: GET\u8bf7\u6c42\u793a\u4f8b\r\n      request:\r\n        method: GET\r\n        url: http://httpbin.org/get\r\n      validate:\r\n        - eq: [status_code, 200]\r\n\r\n    test1:\r\n        name: \u7528\u4f8b1\r\n        print: hello 11111\r\n\r\n    test2:\r\n        name: \u7528\u4f8b2\r\n        print: hello 22222\r\n\r\n\u7528\u4f8b\u90e8\u5206\u652f\u63012\u79cd\u683c\u5f0f\uff0c\u53ef\u4ee5\u662f\u4e00\u4e2a\u952e\u503c\u5bf9\u683c\u5f0f\r\n\r\n::\r\n\r\n    test1:\r\n        name: \u7528\u4f8b1\r\n        print: hello 11111\r\n\r\n\r\n\u4e5f\u53ef\u4ee5\u662f\u4e00\u4e2alist\r\n\r\n\r\n::\r\n\r\n    test1:\r\n     -\r\n        name: \u7528\u4f8b1\r\n        print: hello 11111\r\n\r\n\u5982\u679c\u7528\u591a\u4e2a\u6b65\u9aa4\u6b65\u9aa4\u9700\u8981\u6267\u884c\uff0c\u90a3\u4e48\u7528\u4f8b\u5e94\u8be5\u662f\u4e00\u4e2alist\uff0c\u4f1a\u6309\u987a\u5e8f\u53bb\u6267\u884c\r\n\r\n::\r\n\r\n    config:\r\n        name: demo\r\n\r\n\r\n    test1:\r\n        name: \u7528\u4f8b1\r\n        print: hello 11111\r\n\r\n    test2:\r\n    -\r\n        name: get\r\n        request:\r\n            method: GET\r\n            url: http://httpbin.org/get\r\n        validate:\r\n          - eq: [status_code, 200]\r\n\r\n    -\r\n        name: post\r\n        request:\r\n            method: POST\r\n            url: http://httpbin.org/post\r\n            json:\r\n              username: test\r\n              password: \"123456\"\r\n        validate:\r\n          - eq: [status_code, 200]\r\n\r\nlogging \u65e5\u5fd7\r\n--------------------------\r\n\r\npytest \u7684\u65e5\u5fd7\u52062\u4e2a\u90e8\u5206\uff1a\r\n\r\n- console \u63a7\u5236\u53f0\u8f93\u51fa\u7684\u65e5\u5fd7\r\n- log_file  \u4fdd\u5b58\u5230\u672c\u5730\u6587\u4ef6\u7684\u65e5\u5fd7\r\n\r\n\u672c\u63d2\u4ef6\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u4f1a\u8bb0\u5f55\u8fd0\u884c\u65e5\u5fd7\u4fdd\u5b58\u5728\u9879\u76ee\u6839\u76ee\u5f55logs\u4e0b\uff0c\u4ee5\u5f53\u524d\u65f6\u95f4\u4fdd\u5b58txt\u6587\u672c\u65e5\u5fd7\u5185\u5bb9\u3002\r\n\u65e5\u5fd7\u9ed8\u8ba4\u4fdd\u5b58info\u7ea7\u522b\u3002\r\nconsole \u63a7\u5236\u53f0\u9ed8\u8ba4\u4e0d\u8f93\u51fa\u65e5\u5fd7\r\n\r\n\u5f00\u542f console \u63a7\u5236\u53f0\u65e5\u5fd7\r\n\r\n\u63a7\u5236\u53f0\u76f4\u63a5\u8fd0\u884c pytest \u662f\u4e0d\u4f1a\u7528\u65e5\u5fd7\u8f93\u51fa\u7684\uff0c\u56e0\u4e3a\u9ed8\u8ba4\u4ec5\u8f93\u51fa warning \u4ee5\u4e0a\u7684\u7ea7\u522b\u65e5\u5fd7\r\n\u67093\u79cd\u65b9\u5f0f\u542f\u52a8 console \u65e5\u5fd7\r\n\r\n\u65b9\u6cd51\uff1a\u547d\u4ee4\u884c\u5e26\u4e0a`--log-cli-level`\u53c2\u6570\uff0c\u8bbe\u7f6e\u65e5\u5fd7\u7ea7\u522b\r\n\r\n::\r\n\r\n  >pytest --log-cli-level=info\r\n\r\n\u65b9\u6cd52\uff1a pytest.ini \u914d\u7f6e\u5f00\u542f\u65e5\u5fd7\uff0c\u5e76\u4e14\u8bbe\u7f6e\u65e5\u5fd7\u7ea7\u522b\r\n\r\n::\r\n\r\n    [pytest]\r\n\r\n    log_cli = true\r\n    log_cli_level = info\r\n\r\n\u65b9\u6cd53\uff1a pytest -o\u65b9\u5f0f\u91cd\u5199\uff08\u5373\u8986\u76d6ini\u6587\u4ef6\u4e2d\u7684log\u76f8\u5173\u7684\u547d\u4ee4\u884c\u53c2\u6570\uff09\r\n\r\n::\r\n\r\n    pytest -o log_cli=true -o log_cli_level=INFO\r\n\r\n\r\n\u5373\u53ef\u5728\u63a7\u5236\u53f0\u770b\u5230\u65e5\u5fd7\r\n\r\n::\r\n\r\n    -------------------------------------------- live log call --------------------------------------------\r\n    2022-12-08 08:30:34 [INFO]: \u6267\u884c\u6587\u4ef6-> test_demo.yml\r\n    2022-12-08 08:30:34 [INFO]: base_url-> None\r\n    2022-12-08 08:30:34 [INFO]: variables-> {}\r\n    2022-12-08 08:30:34 [INFO]: \u8fd0\u884c teststeps\r\n    2022-12-08 08:30:34 [INFO]: --------  request info ----------\r\n    POST http://httpbin.org/post\r\n    {\r\n      \"method\": \"POST\",\r\n      \"url\": \"http://httpbin.org/post\",\r\n      \"json\": {\r\n        \"username\": \"test\",\r\n        \"password\": \"123456\"\r\n      }\r\n    }\r\n    2022-12-08 08:30:35 [INFO]: ------  response info  200 OK  0.495961s------\r\n\r\n\r\n\u81ea\u5b9a\u4e49 console \u63a7\u5236\u53f0\u65e5\u5fd7\r\n\r\n\u65e5\u5fd7\u7684\u683c\u5f0f\u548c\u65f6\u95f4\u683c\u5f0f\u4e5f\u53ef\u4ee5\u81ea\u5b9a\u4e49\u8bbe\u7f6e\r\n\r\n::\r\n\r\n    [pytest]\r\n\r\n    log_cli = true\r\n    log_cli_level = info\r\n    log_cli_format = %(asctime)s %(filename)s:%(lineno)s [%(levelname)s]: %(message)s\r\n    log_cli_date_format = %Y-%m-%d %H:%M:%S\r\n\r\n\r\n\u81ea\u5b9a\u4e49\u4fdd\u5b58\u65e5\u5fd7\u6587\u4ef6\r\n\r\n\u672c\u63d2\u4ef6\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u4f1a\u8bb0\u5f55\u8fd0\u884c\u65e5\u5fd7\u4fdd\u5b58\u5728\u9879\u76ee\u6839\u76ee\u5f55logs\u4e0b\uff0c\u4ee5\u5f53\u524d\u65f6\u95f4\u4fdd\u5b58txt\u6587\u672c\u65e5\u5fd7\u5185\u5bb9\u3002\r\n\u65e5\u5fd7\u9ed8\u8ba4\u4fdd\u5b58info\u7ea7\u522b\u3002\r\n\r\n\u5982\u679c\u4f60\u60f3\u6539\u53d8\u8fd9\u4e9b\u9ed8\u8ba4\u7684\u884c\u4e3a\uff0c\u81ea\u5b9a\u4e49\u65e5\u5fd7\u6587\u4ef6\u76ee\u5f55\u548c\u540d\u79f0\uff0c\u53ef\u4ee5\u5728pytest.ini \u914d\u7f6e\u65e5\u5fd7\u6587\u4ef6\r\n(log_file \u76f8\u5173\u7684\u7ed3\u679c\u662f\u4fdd\u5b58\u65e5\u5fd7\u6587\u4ef6\u5230\u672c\u5730)\r\n\r\n::\r\n\r\n    [pytest]\r\n\r\n    log_cli = true\r\n    log_cli_level = info\r\n    log_cli_format = %(asctime)s %(filename)s:%(lineno)s [%(levelname)s]: %(message)s\r\n    log_cli_date_format = %Y-%m-%d %H:%M:%S\r\n\r\n    log_file = ./yoyo.log\r\n    log_file_level = debug\r\n    log_file_format = %(asctime)s %(filename)s:%(lineno)s [%(levelname)s]: %(message)s\r\n    log_file_date_format = %Y-%m-%d %H:%M:%S\r\n\r\n\r\n\u547d\u4ee4\u884c\u53c2\u6570\u914d\u7f6e\r\n\r\nlog\u65e5\u5fd7\u7684\u914d\u7f6e\u4e5f\u53ef\u4ee5\u7528\u547d\u4ee4\u884c\u53c2\u6570\u914d\u7f6e(pytest -h\u53ef\u4ee5\u67e5\u770b)\r\n\r\n::\r\n\r\n     --no-print-logs       \u3000\u3000\u3000\u3000\u3000\u3000 disable printing caught logs on failed tests.\r\n     --log-level=LOG_LEVEL     \u3000\u3000\u3000\u3000logging level used by the logging module\r\n     --log-format=LOG_FORMAT\u3000\u3000\u3000\u3000\u3000\u3000log format as used by the logging module.\r\n     --log-date-format=LOG_DATE_FORMAT\u3000\u3000\u3000\u3000\u3000\u3000log date format as used by the logging module.\r\n     --log-cli-level=LOG_CLI_LEVEL\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000cli logging level.\r\n     --log-cli-format=LOG_CLI_FORMAT\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000log format as used by the logging module.\r\n     --log-cli-date-format=LOG_CLI_DATE_FORMAT\u3000\u3000\u3000\u3000\u3000\u3000log date format as used by the logging module.\r\n     --log-file=LOG_FILE   \u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000path to a file when logging will be written to.\r\n     --log-file-level=LOG_FILE_LEVEL\u3000\u3000\u3000\u3000\u3000\u3000log file logging level.\r\n     --log-file-format=LOG_FILE_FORMAT\u3000\u3000\u3000\u3000\u3000\u3000log format as used by the logging module.\r\n     --log-file-date-format=LOG_FILE_DATE_FORMAT\u3000\u3000\u3000\u3000\u3000\u3000log date format as used by the logging module.\r\n\r\n\r\n\u8fd8\u53ef\u4ee5\u4f7f\u7528 `pytest -o` \u65b9\u5f0f\u91cd\u5199\uff08\u5373\u8986\u76d6 ini \u6587\u4ef6\u4e2d\u7684 log \u76f8\u5173\u7684\u547d\u4ee4\u884c\u53c2\u6570\uff09\r\n\r\n::\r\n\r\n  pytest pytest  test_log.py -o log_cli=true -o log_cli_level=INFO\r\n\r\n\r\nallure  \u62a5\u544a\r\n-----------------------\r\n\r\n\u672c\u63d2\u4ef6\u662f\u57fa\u4e8epytest\u6846\u67b6\u5f00\u53d1\u7684\uff0c\u6240\u4ee5pytest \u7684\u63d2\u4ef6\u90fd\u80fd\u4f7f\u7528\uff0c\u751f\u6210\u62a5\u544a\u53ef\u4ee5\u7528\u5230 allure \u62a5\u544a\r\nallure \u62a5\u544a\u529f\u80fd\u5728 v1.0.8 \u7248\u672c\u4e0a\u5b9e\u73b0\r\n\r\nallure \u547d\u4ee4\u884c\u5de5\u5177\r\n\r\n- allure \u662f\u4e00\u4e2a\u547d\u4ee4\u884c\u5de5\u5177\uff0c\u9700\u8981\u53bbgithub\u4e0a\u4e0b\u8f7d\u6700\u65b0\u7248[https://github.com/allure-framework/allure2/releases](https://github.com/allure-framework/allure2/releases)\r\n- allure  \u547d\u4ee4\u884c\u5de5\u5177\u662f\u9700\u8981\u4f9d\u8d56jdk \u73af\u5883\uff0c\u73af\u5883\u5185\u5bb9\u81ea\u5df1\u53bb\u642d\u5efa\u4e86\r\n\r\n\u751f\u6210 allure \u62a5\u544a\r\n\r\n\u5728\u7528\u4f8b\u6240\u5728\u7684\u76ee\u5f55\u6267\u884c\u547d\u4ee4, `--alluredir` \u662f\u6307\u5b9a\u62a5\u544a\u751f\u6210\u7684\u76ee\u5f55\r\n\r\n::\r\n\r\n    pytest --alluredir ./report\r\n\r\n\r\n\u6253\u5f00allure \u62a5\u544a\u6267\u884c\u547d\u4ee4\r\n::\r\n\r\n    allure serve ./report\r\n\r\n\u5168\u5c40 base_url\r\n---------------------\r\n\r\n\u4e00\u4e2a\u5b8c\u6574\u7684url \u5730\u5740\u7531\u73af\u5883\u5730\u5740\u548c\u63a5\u53e3\u5730\u5740\u62fc\u63a5\u800c\u6210\uff0c\u73af\u5883\u5730\u5740\u662f\u53ef\u53d8\u7684\uff0c\u53ef\u4ee5\u90e8\u7f72\u5230\u6d4b\u8bd5\u73af\u5883\uff0cuat\u8054\u8c03\u73af\u5883\u7b49\u4e0d\u540c\u7684\u73af\u5883\u3002\r\n\u4e0d\u7ba1\u90e8\u7f72\u5230\u54ea\u4e2a\u73af\u5883\uff0c\u63a5\u53e3\u7684\u5730\u5740\u662f\u4e0d\u53ef\u53d8\u7684\uff0c\u901a\u5e38\u9700\u8981\u4e00\u4e2a\u5168\u5c40base_url \u5730\u5740\u505a\u5230\u73af\u5883\u53ef\u5207\u6362\u3002\r\npip \u5b89\u88c5\u63d2\u4ef6\r\n\r\n::\r\n\r\n    pip install pytest-yaml-yoyo\r\n\r\n\r\nbase_url \u5168\u5c40\u914d\u7f6e\u529f\u80fd\u5728 v1.0.9 \u7248\u672c\u4e0a\u5b9e\u73b0\r\n\r\n\u5728\u63a5\u53e3\u6d4b\u8bd5\u4e2d\uff0c\u901a\u5e38\u4f1a\u628a\u73af\u5883 base_url \u5730\u5740\u72ec\u7acb\u51fa\u6765\r\n\u6bd4\u5982\u4e00\u4e2a\u5b8c\u6574\u7684\u8bf7\u6c42`http://httpbin.org/get` \u90a3\u4e48\u53ef\u4ee5\u5206\u6210\u73af\u5883\u5730\u5740`http://httpbin.org` \u548c \u63a5\u53e3\u5730\u5740 `/get`\r\n\r\n\u5728 yaml \u7528\u4f8b\u4e2d\uff0c\u53ef\u4ee5\u628a base_url \u5355\u72ec\u62ff\u51fa\u6765\u653e\u5230 config \u4e0b\r\n\r\n::\r\n\r\n    config:\r\n      base_url: http://httpbin.org\r\n\r\n    get\u793a\u4f8b:\r\n      name: get demo\r\n      request:\r\n        method: GET\r\n        url: /get\r\n      validate:\r\n        - eq: [status_code, 200]\r\n\r\n    post\u793a\u4f8b:\r\n      name: get demo\r\n      request:\r\n        method: POST\r\n        url: /post\r\n      validate:\r\n        - eq: [status_code, 200]\r\n\r\n\r\n\u5168\u5c40 base_url \u914d\u7f6e\r\n\r\n\u4ece\u9879\u76ee\u7684\u89d2\u5ea6\u8bb2\uff0c\u6d4b\u8bd5\u9879\u76ee\u63a5\u53e3\u7684 base_url \u90fd\u662f\u4e00\u6837\u7684\uff0c\u6240\u4ee5\u6211\u4eec\u53ea\u9700\u5168\u5c40\u8bbe\u7f6e\u4e00\u4e2a\u5c31\u884c\u4e86\uff0c\u4e0d\u9700\u8981\u6bcf\u4e2ayaml \u6587\u4ef6\u4e2d\u91cd\u590d\u53bb\u5199\u3002\r\n\u4e8e\u662f\u53ef\u4ee5\u5728 pytest.ini \u91cc\u9762\u914d\u7f6e\u5168\u5c40base_url\r\n\r\n::\r\n\r\n    [pytest]\r\n\r\n    base_url = http://httpbin.org\r\n\r\n\r\n\u90a3\u4e48yaml\u7528\u4f8b\u5c31\u4e0d\u9700\u8981\u5199 base_url \u4e86\uff0c\u9ed8\u8ba4\u4f1a\u5f15\u7528 pytest.ini \u7684\u5168\u5c40\u914d\u7f6e\r\n",
    "bugtrack_url": null,
    "license": "proprietary",
    "summary": "http/https API run by yaml",
    "version": "1.2.7",
    "project_urls": {
        "Homepage": "https://github.com/yoyoketang/pytest-yaml-yoyo"
    },
    "split_keywords": [
        "pytest",
        "py.test",
        "pytest-yaml",
        "pytest-yaml-yoyo"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "90baae818d7140fe3b4bf9d20b2e92630ee49c9f399ccd52520be458a84cc95b",
                "md5": "01364eed3131977277deed663ecb65f4",
                "sha256": "ec098b95c799a7b252797a169b3ec1c701cd61d8474a8cd714f54854a7020f4d"
            },
            "downloads": -1,
            "filename": "pytest_yaml_yoyo-1.2.7-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "01364eed3131977277deed663ecb65f4",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": ">=3.8",
            "size": 34617,
            "upload_time": "2023-06-19T14:01:01",
            "upload_time_iso_8601": "2023-06-19T14:01:01.192615Z",
            "url": "https://files.pythonhosted.org/packages/90/ba/ae818d7140fe3b4bf9d20b2e92630ee49c9f399ccd52520be458a84cc95b/pytest_yaml_yoyo-1.2.7-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "467ab95640b4b312ec6256944f30ecfc474d6c9c2aa005950dc50e6a7f81a05d",
                "md5": "3f8589ccad0f3c469876448ffe317e22",
                "sha256": "974459eb75d1321ec578065eb99197c65bd95ca918e731a55d19e24d418384af"
            },
            "downloads": -1,
            "filename": "pytest-yaml-yoyo-1.2.7.tar.gz",
            "has_sig": false,
            "md5_digest": "3f8589ccad0f3c469876448ffe317e22",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 37640,
            "upload_time": "2023-06-19T14:01:03",
            "upload_time_iso_8601": "2023-06-19T14:01:03.359837Z",
            "url": "https://files.pythonhosted.org/packages/46/7a/b95640b4b312ec6256944f30ecfc474d6c9c2aa005950dc50e6a7f81a05d/pytest-yaml-yoyo-1.2.7.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-06-19 14:01:03",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "yoyoketang",
    "github_project": "pytest-yaml-yoyo",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "Jinja2",
            "specs": [
                [
                    "==",
                    "3.1.2"
                ]
            ]
        },
        {
            "name": "jmespath",
            "specs": [
                [
                    "==",
                    "1.0.1"
                ]
            ]
        },
        {
            "name": "jsonpath",
            "specs": [
                [
                    "==",
                    "0.82"
                ]
            ]
        },
        {
            "name": "pytest",
            "specs": [
                [
                    "==",
                    "7.2.0"
                ]
            ]
        },
        {
            "name": "PyYAML",
            "specs": [
                [
                    "==",
                    "6.0"
                ]
            ]
        },
        {
            "name": "requests",
            "specs": [
                [
                    "==",
                    "2.28.1"
                ]
            ]
        }
    ],
    "lcname": "pytest-yaml-yoyo"
}
        
Elapsed time: 0.07743s