加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
README.rst 18.24 KB
一键复制 编辑 原始数据 按行查看 历史
yoyo 提交于 2022-12-09 10:35 . 文档更新

pypi_seed

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

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

  • 1、基于 pytest 框架安装插件即可使用,环境非常简单
  • 2、只需要写 yaml 文件用例即可运行,使用 pytest 运行的命令
  • 3、extract 功能实现多个接口步骤的参数关联
  • 4、全局仅登录一次,在用例中自动在请求头部添加Authentication token认证
  • 5、用例参数化 parameters 功能实现
  • 6、yaml 中调用 fixture 功能实现
  • 7、yaml 中调用辅助函数功能使用
  • 8、yaml 中调用 hooks 功能
  • 9、用例分层机制:API和用例层
  • 10、支持 allure 报告

联系我们

作者-上海悠悠 微信/QQ交流:283340479 blog地址 https://www.cnblogs.com/yoyoketang/

版本变更记录

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 生成报告

Installation / 安装

最近环境体验

  • Python 3.8 版本
  • 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 报告

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

pytest --alluredir ./report

打开allure 报告执行命令

allure serve ./report
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化