'2.0版本更新'
|
@ -0,0 +1 @@
|
|||
75326e83b55ea4a745898a117ce7ef34b5e1
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2021/11/18 23:05
|
||||
# @Time : 2022/3/29 17:31
|
||||
# @Author : 余少琪
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2022/3/30 13:32
|
||||
# @Author : 余少琪
|
||||
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class AllureAttachmentType(Enum):
|
||||
"""
|
||||
allure 报告的文件类型枚举
|
||||
"""
|
||||
TEXT = "txt"
|
||||
CSV = "csv"
|
||||
TSV = "tsv"
|
||||
URI_LIST = "uri"
|
||||
|
||||
HTML = "html"
|
||||
XML = "xml"
|
||||
JSON = "json"
|
||||
YAML = "yaml"
|
||||
PCAP = "pcap"
|
||||
|
||||
PNG = "png"
|
||||
JPG = "jpg"
|
||||
SVG = "svg"
|
||||
GIF = "gif"
|
||||
BMP = "bmp"
|
||||
TIFF = "tiff"
|
||||
|
||||
MP4 = "mp4"
|
||||
OGG = "ogg"
|
||||
WEBM = "webm"
|
||||
|
||||
PDF = "pdf"
|
||||
|
||||
@staticmethod
|
||||
def attachment_types():
|
||||
return list(map(lambda c: c.value, AllureAttachmentType))
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2022/3/29 18:03
|
||||
# @Author : 余少琪
|
||||
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class AssertType(Enum):
|
||||
EQUAL = "=="
|
||||
NOTEQUAL = "!="
|
||||
IN = "IN"
|
||||
NO_TIN = "NOTIN"
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2022/3/29 17:32
|
||||
# @Author : 余少琪
|
||||
from enum import Enum, unique
|
||||
|
||||
|
||||
@unique
|
||||
class DependentType(Enum):
|
||||
"""
|
||||
数据依赖相关枚举
|
||||
"""
|
||||
# 依赖响应中数据
|
||||
RESPONSE = 'response'
|
||||
# 依赖请求中的数据
|
||||
REQUEST = 'request'
|
||||
# 依赖sql中的数据
|
||||
SQL_DATA = 'sqlData'
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2022/3/30 23:06
|
||||
# @Author : 余少琪
|
||||
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class NotificationType(Enum):
|
||||
""" 自动化通知方式 """
|
||||
# 默认通知: 不发送
|
||||
DEFAULT = 0
|
||||
# 钉钉通知
|
||||
DING_TALK = 1
|
||||
# 微信通知
|
||||
WECHAT = 2
|
||||
# 邮箱通知
|
||||
EMAIL = 3
|
||||
# 飞书通知
|
||||
FEI_SHU = 4
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2022/3/29 17:42
|
||||
# @Author : 余少琪
|
||||
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class RequestType(Enum):
|
||||
"""
|
||||
request请求发送,请求参数的数据类型
|
||||
"""
|
||||
# json 类型
|
||||
JSON = "JSON"
|
||||
# PARAMS 类型
|
||||
PARAMS = "PARAMS"
|
||||
# data 类型
|
||||
DATE = "DATE"
|
||||
# 文件类型
|
||||
FILE = 'FILE'
|
|
@ -0,0 +1,46 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2022/3/29 17:51
|
||||
# @Author : 余少琪
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class YAMLDate(Enum):
|
||||
"""
|
||||
测试用例相关字段
|
||||
"""
|
||||
# host 配置
|
||||
HOST = 'host'
|
||||
# 接口请求的url
|
||||
URL = 'url'
|
||||
# 请求方式
|
||||
METHOD = 'method'
|
||||
# 请求头
|
||||
HEADER = 'headers'
|
||||
# 请求类型
|
||||
REQUEST_TYPE = 'requestType'
|
||||
# 是否执行
|
||||
IS_RUN = 'is_run'
|
||||
# 请求参数
|
||||
DATA = 'data'
|
||||
# 是否依赖用例
|
||||
DEPENDENCE_CASE = 'dependence_case'
|
||||
# 依赖用例参数
|
||||
DEPENDENCE_CASE_DATA = 'dependence_case_data'
|
||||
# 断言内容
|
||||
ASSERT = 'assert'
|
||||
# sql内容
|
||||
SQL = 'sql'
|
||||
# 用例ID
|
||||
CASE_ID = 'case_id'
|
||||
# jsonpath提取
|
||||
JSONPATH = 'jsonpath'
|
||||
# 替换的内容
|
||||
REPLACE_KEY = 'replace_key'
|
||||
# 依赖数据类型
|
||||
DEPENDENT_TYPE = 'dependent_type'
|
||||
# 用例描述
|
||||
DETAIL = 'detail'
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 187 KiB |
After Width: | Height: | Size: 2.1 KiB |
602
README.md
|
@ -1,6 +1,6 @@
|
|||
## 框架介绍
|
||||
|
||||
本框架主要是基于 Python + pytest + allure + log + yaml + mysql + 钉钉通知 + Jenkins 实现的接口自动化框架。
|
||||
本框架主要是基于 Python + pytest + allure + log + yaml + mysql + redis + 钉钉通知 + Jenkins 实现的接口自动化框架。
|
||||
|
||||
* git地址: [https://gitee.com/yu_xiao_qi/pytest-auto-api](https://gitee.com/yu_xiao_qi/pytest-auto-api)
|
||||
* 项目参与者: 余少琪
|
||||
|
@ -9,11 +9,18 @@
|
|||
|
||||
如果对您有帮助,请点亮 小星星 以表支持,谢谢
|
||||
|
||||

|
||||
|
||||
## 框架优势
|
||||
## 前言
|
||||
公司突然要求你做自动化,但是没有代码基础不知道怎么做?或者有自动化基础,但是不知道如何系统性的做自动化,
|
||||
放在yaml文件中维护,不知道如何处理多业务依赖的逻辑?
|
||||
|
||||
本框架不收取任何费用, 其优势在于测试人员直接编写测试用例,运行框架可自动生成测试代码。
|
||||
框架支持多环境、多角色任意切换,支持接口响应断言以及数据库断言。
|
||||
那么这里 Gitte 中开源的自动化框架,将为你解决这些问题。
|
||||
框架主要使用 python 语言编写,结合 pytest 进行二次开发,用户仅需要在 yaml 文件中编写测试用例,
|
||||
编写成功之后,会自动生成 pytest 的代码,零基础代码小白,也可以操作。
|
||||
|
||||
本框架支持多业务接口依赖,多进程执行,mysql 数据库断言和 接口响应断言,并且用例直接在yaml文件中维护,无需编写业务代码,
|
||||
接口pytest框架生成allure报告,并且发送 企业微信通知/ 钉钉通知/ 邮箱通知/ 飞书通知,灵活配置。
|
||||
|
||||
## 实现功能
|
||||
|
||||
|
@ -34,27 +41,49 @@
|
|||
│ ├── conf.yaml // 公共配置
|
||||
│ ├── setting.py // 环境路径存放区域
|
||||
├── data // 测试用例数据
|
||||
├── docs // 文档
|
||||
├── lib // 对象层,用作于接口的调用
|
||||
├── Enums // 枚举层,用于存放项目中所需的枚举
|
||||
├── File // 上传文件接口所需的文件存放区域
|
||||
├── log // 日志层
|
||||
├── report // 测试报告层
|
||||
├── test_case // 测试用例代码
|
||||
├── tool // 所有公共模块的封装
|
||||
│ └── allureDataControl.py // allure报告数据清洗
|
||||
│ └── assertControl.py // 断言模块
|
||||
│ └── cacheControl.py // 缓存模块
|
||||
│ └── dingtalkControl.py // 钉钉发送通知
|
||||
│ └── excelControl.py // 读取excel文件
|
||||
│ └── gettimeControl.py // 时间模块
|
||||
│ └── logControl.py // 日志模块
|
||||
│ └── logDecorator.py // 日志装饰器
|
||||
│ └── mysqlControl.py // 数据库模块
|
||||
│ └── regularControl.py // 正则模块
|
||||
│ └── requestControl.py // 请求模块
|
||||
│ └── runtimeControl.py // 响应时长统计模块
|
||||
│ └── sendmailControl.py // 发送邮件
|
||||
│ └── testcaseAutomaticControl.py // 自动生成测试代码
|
||||
│ └── yamlControl.py // yaml文件
|
||||
├── utils // 工具类
|
||||
│ └── assertUtils // 断言
|
||||
│ └── assertUtils .py
|
||||
│ └── cacheUtils // 缓存处理模块
|
||||
│ └── cacheControl.py
|
||||
│ └── redisControl.py
|
||||
│ └── logUtils // 日志处理模块
|
||||
│ └── logControl.py
|
||||
│ └── logDecoratrol.py // 日志装饰器
|
||||
│ └── runTimeDecoratrol.py // 统计用例执行时长装饰器
|
||||
│ └── mysqlUtils // 数据库模块
|
||||
│ └── get_sql_data.py
|
||||
│ └── mysqlControl.py
|
||||
│ └── noticUtils // 通知模块
|
||||
│ └── dingtalkControl.py // 钉钉通知
|
||||
│ └── feishuControl.py // 飞书通知
|
||||
│ └── sendmailControl.py // 邮箱通知
|
||||
│ └── weChatSendControl.py // 企业微信通知
|
||||
│ └── otherUtils // 其他工具类
|
||||
│ └── allureDate // allure封装
|
||||
│ └── allure_report_data.py // allure报告数据清洗
|
||||
│ └── allure_tools..py // allure 方法封装
|
||||
│ └── localIpControl.py // 获取本地IP
|
||||
│ └── threadControl.py // 定时器类
|
||||
│ └── readFilesUtils // 文件操作
|
||||
│ └── caseAutomaticControl.py // 自动生成测试代码
|
||||
│ └── clean_files.py // 清理文件
|
||||
│ └── excelControl.py // 读写excel
|
||||
│ └── get_all_files_path.py // 获取所有文件路径
|
||||
│ └── get_yaml_data_analysis.py // yaml用例数据清洗
|
||||
│ └── regularControl.py // 正则
|
||||
│ └── yamlControl.py // yaml文件读写
|
||||
│ └── recordingUtils // 代理录制
|
||||
│ └── mitmproxyContorl..py
|
||||
│ └── requestsUtils
|
||||
│ └── dependentCase.py // 数据依赖处理
|
||||
│ └── requestControl..py // 请求封装
|
||||
│ └── timeUtils
|
||||
├── Readme.md // help
|
||||
├── pytest.ini
|
||||
├── run.py // 运行入口
|
||||
|
@ -99,140 +128,433 @@
|
|||
xlutils==2.0.0
|
||||
xlwt==1.3.0
|
||||
|
||||
#### 安装Python、Pip环境,创建虚拟环境
|
||||
```
|
||||
一、安装Python环境
|
||||
|
||||
# 1、下载Python程序
|
||||
# Python包地址:https://www.python.org/ftp/python/
|
||||
wget https://www.python.org/ftp/python/3.8.5/Python-3.8.5.tgz
|
||||
|
||||
# 2、解压Python-3.8.5.tgz
|
||||
tar -zxvf Python-3.8.5.tgz
|
||||
|
||||
# 3、编译安装
|
||||
sudo mkdir /usr/local/python3.8.5
|
||||
cd Python-3.8.5
|
||||
sudo ./configure --prefix=/usr/local/python3.8.5
|
||||
sudo make && sudo make install
|
||||
|
||||
# 4、建立软链接
|
||||
sudo ln -s /usr/local/python3.8.5/bin/python3 /usr/bin/python3
|
||||
sudo ln -s /usr/local/python3.8.5/bin/pip3 /usr/bin/pip3
|
||||
|
||||
# 5、验证安装
|
||||
python3 -V
|
||||
pip3 -V
|
||||
|
||||
二、安装虚拟环境、创建虚拟环境
|
||||
# 1、安装虚拟环境virtualenv
|
||||
yum install -y python-virtualenv
|
||||
|
||||
# 2、创建虚拟环境
|
||||
# 在项目根目录创建虚拟环境
|
||||
virtualenv -p python3 venv
|
||||
|
||||
# 3、激活虚拟环境
|
||||
source ./venv/bin/activate
|
||||
|
||||
# 4、退出虚拟环境
|
||||
deactivate
|
||||
```
|
||||
|
||||
## 安装教程
|
||||
|
||||
输入如下命令,安装本框架的所有第三方库依赖
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
||||
## 使用说明
|
||||
## 用例中相关字段的介绍
|
||||
|
||||
### config-->conf.yaml
|
||||

|
||||
|
||||

|
||||
上方截图,就是一个用例中需要维护的相关字段,下面我会对每个字段的作用,做出解释。
|
||||
|
||||
首先是配置文件,这里主要存放了一个公共的配置数据,如项目名称、钉钉、邮箱、企业微信、数据库等相关的配置全部都在这里
|
||||
所有的字段,在conf.yaml中,都有相关的注释,自行修改即可。
|
||||
1、case_common: 这个公共参数的维护,方便后期如有需要新增的字段,可以添加在公共参数中,
|
||||
目前只有三个:allureEpic、allureFeature、allureStory,
|
||||
这三个都是allure报告需要用到的装饰器内容,后续自动生成 pytest 中 test_case 会用到这三个参数值。
|
||||
2、spu_apply_list_01: 用例ID,唯一
|
||||
3、host: 接口的域名: 填写规则如下 ${{host}},执行脚本时,会去读取conf.yaml 文件中配置域名
|
||||
4、url: 接口路径
|
||||
5、header: 请求头
|
||||
6、requestType: 请求参数类型,有json、file、params、data四种类型
|
||||
7、is_run: 是否执行,为空、或者 True 都会执行
|
||||
8、data: 请求参数,所有的请求参数,全部放在 data 下方
|
||||
9、dependence_case:判断该条用力,是否有依赖业务,如为空或者 false 则表示没有
|
||||
10、dependence_case_data:依赖用例中需要的相关数据(下方数据依赖示例中,会对该字段下方的内容,做详细介绍)
|
||||
11、assert: 断言,支持判断sql、或者接口响应内容。
|
||||
12、sql:该用例中所需使用的sql
|
||||
|
||||
目前框架主要是用的企业微信通知,在用例执行成功之后发送通知,通知内容如下,可以根据公司主要使用的通讯工具自行更改。
|
||||
在公共方法中分别封装了钉钉通知、以及邮箱通知。
|
||||
### 如何发送get请求
|
||||
上方了解了用例的数据结构之后,下面我们开始编写第一个get请求方式的接口。
|
||||
首先,开始编写项目之后,我们在 conf.yaml 中配置项目的域名
|
||||
|
||||
# 注意点:
|
||||
# 之前为了小伙伴们拉下代码执行的时候不受影响,企业微信、钉钉、邮箱的通知配置的都是我的
|
||||
# 我发现很多拉代码的小伙伴这里配置都没改,所有的通知都发到我这里来了哦~~麻烦看到这里的小伙伴自己在conf.yaml改一下相关配置
|
||||

|
||||
|
||||

|
||||
域名配置好之后,我们来编写测试用例,在 data 文件下面,创建一个名称为
|
||||
spu_apply_list.yaml 的用例文件,内容如下
|
||||
|
||||
如程序执行执行异常时,会自动收集错误信息,并将内容发送邮件。
|
||||
|
||||

|
||||
|
||||
### config --> setting.py
|
||||
|
||||
setting.py 文件主要是用来存放项目中所有文件的目录地址
|
||||
|
||||
更改过一些公用的配置之后,下面我们来开始编写自动化
|
||||
|
||||
### data 用来存放测试用例
|
||||
|
||||

|
||||
|
||||
上方主要是测试用例,测试用例是整个自动化程序中非常重要的一部分,需要严格按照我上方图中的格式进行编写。
|
||||
下面我会对每个字段依次进行解释对应的作用。
|
||||
|
||||
- url: 请求接口的地址,${{MerchantHost}} 为接口的host,放在conf.yaml 文件中,可以更改成公司项目的host
|
||||
- method: 请求方式,目前支持GET、POST、DELETE、PUT,本人公司目前设计到的请求方式只有这四种,如有需求可自行添加
|
||||
- detail: 用例描述,程序中未强制要求必填,但是最好是每个用例都填写上,打印日志以及生成代码的函数注释,都会依赖用例描述
|
||||
- header: 请求头
|
||||
- requestType: 必填,这个字段主要取决于你请求的是参数是以json、params、file、或者data的格式
|
||||
- data: 请求参数
|
||||
如接口中需要的请求参数全部放在data中
|
||||
- allureEpic: 作用与allure装饰器,必填(如有多个测试用例,只需要写在第一个用例中就行)
|
||||
- allureFeature: 作用于allure装饰器,必填(如有多个测试用例,只需要写在第一个用例中就行)
|
||||
- resp: 响应断言相关的数据
|
||||
- 响应接口的参数字段(如code): code,就是接口的响应状态码,这些参数都是自己加的。
|
||||
- jsonpath: 这里获取到对应的接口数据,主要使用到了jsonpath。如果有不了这一块的,大家可以看我的博客:https://blog.csdn.net/weixin_43865008/article/details/118371620
|
||||
- value: 预期值,这里会根据你前面jsonpath中获取到的响应数据,然后和你添加的预期值进行断言。如果断言失败,会打印对应的日志信息,以及allure测试报告中也会呈现这条用例的失败状态
|
||||
- type: 断言的类型,如判断是否相等,则使用”==“,或者”!=“,则表示内容不相等,”IN“则表示预期值是否在响应值中,对应的还有"NOTIN"
|
||||
- AssertType: 目前自动化支持两种断言类型,接口响应断言和数据库断言。如果是接口响应断言,则AssertType的值可不填,如果值为"SQL"的话,则走数据库断言。为sql的时候,sql查询出来的数据类型是字典类型,因此value值会从sql查询出来的字段中使用jsonpath的形式读取sql查询出来的数据
|
||||
- 如有多个数据,则可像上方图中一样,创建多个字段
|
||||
- sql: sql 是以 LIST 的类型存储的,可以将我们这个接口需要依赖的sql语句全部放在这里,程序中会循环查询出sql中的所有语句,并且返回数据库中的值,从而与接口响应的值做匹配。(这里也是对于sql多表联查不太会的朋友的福音。如果不会多表联查的话,可以编写单表sql,程序中会将所有单表的数据内容全部查询出来)
|
||||
- 接口中如有多条测试用例,则以上方格式为例,添加多个即可。
|
||||
|
||||
## lib---> xxx.py
|
||||
|
||||
假设我们按照上方图中的格式内容,创建了一个用例创建成功之后yaml文件的用例,创建之后下面我们来生成自动化脚本,执行第一条用例。
|
||||

|
||||
|
||||
首先,我们找到tools目录下的 testcaseAutomaticControl.py 文件,然后执行这里的代码
|
||||
|
||||
执行成功之后,我们可以看到lib和test_case目录下,会生成一个和创建用例yaml文件名称一模一样的py文件,test_case名称会以test_开头
|
||||
内容如下:
|
||||

|
||||
|
||||
下面我们就可以开始执行我们的测试用例了,这里生成的文件,主要类似于我们自动化模型中的PO模型,生成的page
|
||||
|
||||
执行之后,我们可以看到下方详细的请求日志信息,方便我们进行用例调试(lie层只是作用域单个接口的调试,如果需要多接口跑业务的话,直接到test_case层去做即可)
|
||||
|
||||

|
||||
|
||||
test_case --> test_apply_verifycode.py
|
||||
|
||||
__用例调试成功之后,下面我们进入编写用例脚本阶段,主要内容如下:__
|
||||
|
||||

|
||||
|
||||
其中代码中关于pytest的相关内容,网上的资料有非常多,并且非常详情,这里不做赘述。
|
||||
|
||||
所有的用例内容,格式都为统一的,目前只能生成单接口的业务用例,如果需要接口执行的话,还需要在case层调用对应业务的接口
|
||||
|
||||
用例添加完成之后,执行run.py,程序会执行所有文件的用例,并且生成测试报告,发送钉钉通知。
|
||||
# 公共参数
|
||||
case_common:
|
||||
allureEpic: 电商平台端
|
||||
allureFeature: 审核中心
|
||||
allureStory: 商品审核列表
|
||||
|
||||
|
||||
### 关于框架未来功能的规划
|
||||
spu_apply_list_01:
|
||||
host: ${{host}}
|
||||
url: /api/v1/work/spu/approval/spuList
|
||||
method: GET
|
||||
detail: 查看商品审核列表
|
||||
headers:
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
token: work_login_init
|
||||
# 请求的数据,是 params 还是 json、或者file
|
||||
requestType: params
|
||||
# 是否执行,空或者 true 都会执行
|
||||
is_run: False
|
||||
data:
|
||||
spuType: 1
|
||||
pageNum: 1
|
||||
pageSize: 10
|
||||
# 是否有依赖业务,为空或者false则表示没有
|
||||
dependence_case:
|
||||
# 依赖的数据
|
||||
dependence_case_data:
|
||||
assert:
|
||||
code:
|
||||
jsonpath: $.code
|
||||
type: ==
|
||||
value: 200
|
||||
AssertType:
|
||||
sql:
|
||||
|
||||
1、计划后期多接口业务逻辑,也统一放在yaml文件中维护,并且生成对应业务逻辑的相关代码
|
||||
2、自动生成代码的功能,计划通过多线程实现
|
||||
get请求我们 requestType 写的是params,这样发送请求时,我们会将请求参数拼接中url中,最终像服务端发送请求的地址格式会为:
|
||||
|
||||
${{host}}/api/v1/work/spu/approval/spuList?supType=1&pageNum=1&pageSize=10
|
||||
|
||||
### 如何发送post请求
|
||||
|
||||
# 公共参数
|
||||
case_common:
|
||||
allureEpic: 盲盒APP
|
||||
allureFeature: 登录模块
|
||||
allureStory: 获取登录验证码
|
||||
|
||||
send_sms_code_01:
|
||||
host: ${{host}}
|
||||
url: /mobile/sendSmsCode
|
||||
method: POST
|
||||
detail: 正常获取登录验证码
|
||||
headers:
|
||||
appId: '23132'
|
||||
masterAppId: masterAppId
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
# 请求的数据,是 params 还是 json、或者file
|
||||
requestType: json
|
||||
# 是否执行,空或者 true 都会执行
|
||||
is_run:
|
||||
data:
|
||||
phoneNumber: "180xxxx9278"
|
||||
# 是否有依赖业务,为空或者false则表示没有
|
||||
dependence_case: False
|
||||
# 依赖的数据
|
||||
dependence_case_data:
|
||||
assert:
|
||||
code:
|
||||
jsonpath: $.code
|
||||
type: ==
|
||||
value: '00000'
|
||||
AssertType:
|
||||
success:
|
||||
jsonpath: $.success
|
||||
type: ==
|
||||
value: true
|
||||
AssertType:
|
||||
|
||||
sql:
|
||||
|
||||
这里post请求,我们需要请求的数据格式是json格式的,那么requestType 则填写为json格式。包括 PUT/DELETE/HEAD 请求的数据格式都是一样的,唯一不同的就是需要配置 reuqestType,如果需要请求的参数是json格式,则requestType我们就填写json,如果是url拼接的形式,我们就填写 params
|
||||
|
||||
### 如何测试上传文件接口
|
||||
|
||||
首先,我们将所有需要测试的文件,全部都放在 files 文件夹中
|
||||

|
||||
|
||||
requestType: file
|
||||
# 是否执行,空或者 true 都会执行
|
||||
is_run:
|
||||
data:
|
||||
file:
|
||||
# file 直接写文件名称
|
||||
files:排入水体名.png
|
||||
|
||||
# 是否有依赖业务,为空或者false则表示没有
|
||||
dependence_case: False
|
||||
|
||||
在yaml文件中,我们需要注意两个地方,主要是用例中的requestType、和 filename 字段:
|
||||
1、requestType: 上传文件,我们需要更改成 file
|
||||
2、filename 参数名称: 上传文件,我们只需要填写files文件夹下的文件名称即可,程序在发送请求时,会去识别文件
|
||||
|
||||
### 多业务逻辑,如何编写测试用例
|
||||
多业务这一块,我们拿个简单的例子举例,比如登录场景,在登陆之前,我们需要先获取到验证码。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
首先,我们先创建一个 get_send_sms_code.yaml 的文件,编写一条发送验证码的用例
|
||||
|
||||
# 公共参数
|
||||
case_common:
|
||||
allureEpic: 盲盒APP
|
||||
allureFeature: 登录模块
|
||||
allureStory: 获取登录验证码
|
||||
|
||||
send_sms_code_01:
|
||||
host: ${{host}}
|
||||
url: /mobile/sendSmsCode
|
||||
method: POST
|
||||
detail: 正常获取登录验证码
|
||||
headers:
|
||||
appId: '23132'
|
||||
masterAppId: masterAppId
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
# 请求的数据,是 params 还是 json、或者file
|
||||
requestType: json
|
||||
# 是否执行,空或者 true 都会执行
|
||||
is_run:
|
||||
data:
|
||||
phoneNumber: "180****9278"
|
||||
# 是否有依赖业务,为空或者false则表示没有
|
||||
dependence_case: False
|
||||
# 依赖的数据
|
||||
dependence_case_data:
|
||||
assert:
|
||||
code:
|
||||
jsonpath: $.code
|
||||
type: ==
|
||||
value: '00000'
|
||||
AssertType:
|
||||
success:
|
||||
jsonpath: $.success
|
||||
type: ==
|
||||
value: true
|
||||
AssertType:
|
||||
|
||||
sql:
|
||||
|
||||
编写好之后,我们在创建一个 login.yaml 文件
|
||||
|
||||
# 公共参数
|
||||
case_common:
|
||||
allureEpic: 盲盒APP
|
||||
allureFeature: 登录模块
|
||||
allureStory: 登录
|
||||
|
||||
login_02:
|
||||
host: ${{host}}
|
||||
url: /login/phone
|
||||
method: POST
|
||||
detail: 登录输入错误的验证码
|
||||
headers:
|
||||
appId: '23132'
|
||||
masterAppId: masterAppId
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
# 请求的数据,是 params 还是 json、或者file
|
||||
requestType: json
|
||||
# 是否执行,空或者 true 都会执行
|
||||
is_run:
|
||||
data:
|
||||
phoneNumber: 18014909278
|
||||
code:
|
||||
# 是否有依赖业务,为空或者false则表示没有
|
||||
dependence_case: True
|
||||
# 依赖的数据
|
||||
dependence_case_data:
|
||||
- case_id: send_sms_code_02
|
||||
dependent_data:
|
||||
- dependent_type: response
|
||||
jsonpath: $.code
|
||||
replace_key: $.data.code
|
||||
|
||||
assert:
|
||||
code:
|
||||
jsonpath: $.code
|
||||
type: ==
|
||||
value: '00000'
|
||||
AssertType:
|
||||
sql:
|
||||
|
||||
其中处理多业务的核心区域,主要在这里:
|
||||
|
||||
dependence_case: True
|
||||
# 依赖的数据
|
||||
dependence_case_data:
|
||||
- case_id: send_sms_code_02
|
||||
dependent_data:
|
||||
- dependent_type: response
|
||||
jsonpath: $.code
|
||||
replace_key: $.data.code
|
||||
|
||||
首先,我们 dependence_case 需要设置成 True,并且在下面的 dependence_case_data 中设计相关依赖的数据。
|
||||
|
||||
1、case_id:上方场景中,我们登录需要先获取验证码,因此依赖的case_id 就是发送短信验证码的 case_id :send_sms_code_02
|
||||
2、dependent_type:我们依赖的是获取短信验证码接口中的响应内容,因此这次填写的是 response
|
||||
3、jsonpath: 通过jsonpath 提取方式,提取到短信验证码中的验证码内容
|
||||
4、replace_key:拿到验证码之后,我们将本条用例中的data中的code参数,那么我们使用jsonpath的方式,进行替换 $.data.code
|
||||
|
||||
### 多业务逻辑,需要依赖同一个接口中的多个数据
|
||||
dependence_case_data:
|
||||
- case_id: send_sms_code_02
|
||||
dependent_data:
|
||||
# 提取接口响应的code码
|
||||
- dependent_type: response
|
||||
jsonpath: $.code
|
||||
replace_key: $.data.code
|
||||
# 提取接口响应的accessToken
|
||||
- dependent_type: response
|
||||
jsonpath: $.data.accessToken
|
||||
# 替换请求头中的accessToken
|
||||
replace_key: $.headers.accessToken
|
||||
|
||||
|
||||
如上方示例,可以添加多个 dependent_type
|
||||
|
||||
### 多业务逻辑,需要依赖不同接口的数据
|
||||
假设我们需要获取 send_sms_code_01、get_code_01两个接口中的数据,用例格式如下
|
||||
|
||||
dependence_case: True
|
||||
# 依赖的数据
|
||||
dependence_case_data:
|
||||
- case_id: send_sms_code_01
|
||||
dependent_data:
|
||||
# 提取接口响应的code码
|
||||
- dependent_type: response
|
||||
jsonpath: $.code
|
||||
replace_key: $.data.code
|
||||
- case_id: get_code_01
|
||||
dependent_data:
|
||||
# 提取接口响应的code码
|
||||
- dependent_type: response
|
||||
jsonpath: $.code
|
||||
replace_key: $.data.code
|
||||
|
||||
### 用例中需要依赖登录的token,如何设计
|
||||
|
||||
首先,为了防止重复请求调用登录接口,pytest中的 conftest.py 提供了热加载机制,看上方截图中的代码,我们需要在 conftest.py 提前编写好登录的代码。
|
||||
|
||||

|
||||
|
||||
如上方代码所示,我们会先去读取login.yaml文件中的用例,然后执行获取到响应中的token,然后 编写 Cache('work_login_init').set_caches(token),将token写入缓存中,其中 work_login_init 是缓存名称。
|
||||
|
||||
编写好之后,我们会在 requestControl.py 文件中,读取缓存中的token,如果该条用例需要依赖token,则直接进行内容替换。
|
||||
|
||||

|
||||
|
||||
这里在编写用例的时候,token 填写我们所编写的缓存名称即可。
|
||||
|
||||
### 用例中如何生成随机数据
|
||||
|
||||
比如我们有些特殊的场景,可能会涉及到一些定制化的数据,每次执行数据,需要按照指定规则随机生成。
|
||||
|
||||

|
||||
|
||||
如上图所示,我们用例中的 reason 审核原因后方,需要展示审核的当前时间。那么我们首先需要封装一个获取当前时间的方法
|
||||
|
||||

|
||||
|
||||
那么我们就在 regularControl.py 文件中,编写 get_time 的方法。编写好之后,在用例中编写规则如下:
|
||||
|
||||
reason: 审核时间${{get_time}}
|
||||
使用 ${{函数名称}}的方法,程序调用时,会生成当前时间。在regularControl.py 文件中,我还封装了一些常用的随机数,如随机生成男生姓名、女生姓名、身份证、邮箱、手机号码之类的,方便大家使用。 如,随机生成邮箱,我们在用例中编写的格式为 ${{get_email}} 。
|
||||
|
||||
其他所需随机生成的数据,可在文件中自行添加。
|
||||
|
||||
|
||||
### 用例中如何进行接口断言和数据库断言
|
||||
|
||||
假设现在我需要测试一个报表统计的数据,该接口返回了任务的处理时长 和 处理数量。功能如下截图所示:
|
||||
|
||||

|
||||
|
||||
假设下方是我们拿到接口响应的数据内容:
|
||||
|
||||
{"code": 200, "times": 155.91, "counts": 9}
|
||||
|
||||
这个时候,我们需要判断该接口返回的数据是否正确,就需要编写sql,对响应内容进行校验。
|
||||
|
||||

|
||||
|
||||
因此我们编写了如上sql,查出对应的数据,那么用例中编写规则如下,下方我们分别断言了两个内容,一个是对接口的响应code码进行断言,一个是断言数据库中的数据。
|
||||
|
||||
|
||||
assert:
|
||||
code:
|
||||
jsonpath: $.code
|
||||
type: ==
|
||||
value: 200
|
||||
# 断言接口响应时,可以为空
|
||||
AssertType:
|
||||
do_time:
|
||||
# jsonpath 拿到接口响应的数据
|
||||
jsonpath: $.times
|
||||
type: ==
|
||||
# sql 查出来的数据,是字典类型的,因此这里是从字段中提取查看出来的字段
|
||||
value: $.do_time
|
||||
# 断言sql的时候,AssertType 的值需要填写成 SQL
|
||||
AssertType: SQL
|
||||
question_counts:
|
||||
jsonpath: $.counts
|
||||
type: ==
|
||||
#
|
||||
value: $.question_counts
|
||||
# 断言sql的时候,AssertType 的值需要填写成 SQL
|
||||
AssertType: SQL
|
||||
sql:
|
||||
- select * from test_goods where shop_id = 515
|
||||
|
||||
我们分别对用例的数据进行讲解,首先是响应断言, 编写规则如下
|
||||
|
||||
code:
|
||||
# 通过jsonpath获取接口响应中的code {"code": 200, "times": 155.91, "counts": 9}
|
||||
jsonpath: $.code
|
||||
type: ==
|
||||
value: 200
|
||||
# 断言接口响应时,可以为空
|
||||
AssertType:
|
||||
|
||||
下面是对sql进行断言
|
||||
|
||||
question_counts:
|
||||
# 断言接口响应的问题上报数量counts {"code": 200, "times": 155.91, "counts": 9}
|
||||
jsonpath: $.counts
|
||||
type: ==
|
||||
# 查询sql,我们数据库查到的数据是一个字段,数据是这样的:{question_counts: 13, do_time: 1482.70}, 这里我们通过 jsonpath获取question_counts
|
||||
value: $.question_counts
|
||||
# 断言sql的时候,AssertType 的值需要填写成 SQL
|
||||
AssertType: SQL
|
||||
sql:
|
||||
- SELECT round( sum(( UNIX_TIMESTAMP( filing_time )- UNIX_TIMESTAMP( report_time )) / 60 ) / 60, 2 ) AS do_time, count( id ) AS question_counts FROM fl_report_info WHERE state IN ( 1, 3 )
|
||||
|
||||
有些细心的小伙伴会发现,我们的sql,是列表类型的。这样就意味这,我们的sql可以同时编写多条,这样会对不会编写多表联查的小伙伴比较友好,可以进行单表查询,获取我们需要的数据。
|
||||
|
||||
sql:
|
||||
- select * from users;
|
||||
- select * from goods;
|
||||
|
||||
### 自动生成test_case层代码
|
||||
|
||||
小伙伴们在编写好 yaml 用例之后,可以直接执行 caseAutomaticControl.py ,会跟你设计的测试用例,生成对应的代码。
|
||||
|
||||

|
||||
|
||||
### 发送钉钉通知通知
|
||||

|
||||
|
||||
### 发送企业微信通知
|
||||

|
||||
|
||||
### 日志打印装饰器
|
||||
|
||||

|
||||
|
||||
在requestControl.py中,我单独封装了一个日志装饰器,需要的小伙伴可以不用改动代码,直接使用,如果不需要,直接注释,或者改成False。控制台将不会有日志输出
|
||||
|
||||
### 统计用例运行时长
|
||||

|
||||
|
||||
同样,这里封装了一个统计用例运行时长的装饰器,使用改装饰器前,需要先进行导包
|
||||
|
||||
from utils.logUtils.runTimeDecoratorl import execution_duration
|
||||
导入之后,调用改装饰器,装饰器中填写的用例执行时长,以毫秒为单位,如这里设置的2000ms,那么如果该用例执行大于2000ms,则会输出一条告警日志。
|
||||
|
||||
@execution_duration(2000)
|
||||
|
||||
### 生成allure报告
|
||||
我们直接运行主程序 run.py ,运行完成之后,就可以生成漂亮的allure报告啦~
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### 其他
|
||||
|
||||
本框架为2.0升级版本,升级之后的功能,现在基本上都是在yaml中维护用例,无需测试人员编写代码,
|
||||
和 1.0版本的区别在于,1.0版本还需要测试人员手动编写多业务逻辑的代码,需要有一定基础编码的能力
|
||||
|
||||
但是1.0版本,同样也可以自动生成代码,yaml中维护数据,对相对简单,如果偏于yaml简单维护的同学,可以切换查看1.0分支
|
||||
下方是1.0分支的操作文档:[点我查看](https://blog.csdn.net/weixin_43865008/article/details/121903028?spm=1001.2014.3001.5502)
|
||||
|
||||
*******************************************************
|
||||
|
||||
|
|
|
@ -2,15 +2,17 @@ ProjectName:
|
|||
- 余少琪的框架
|
||||
-
|
||||
|
||||
Env: 测试环境
|
||||
# 测试人员名称,作用于自动生成代码的作者,以及发送企业微信、钉钉通知的测试负责人
|
||||
TestName: 余少琪
|
||||
TesterName: 余少琪
|
||||
|
||||
# 域名1
|
||||
Host: https://redisdatarecall.csdn.net
|
||||
host: https://www.baidu.com # 域名随便写的,记得修改
|
||||
app_host:
|
||||
# 域名2
|
||||
work:
|
||||
|
||||
# 报告通知类型:1:钉钉 2:企业微信通知 3、邮箱
|
||||
# 报告通知类型:0: 不发送通知 1:钉钉 2:企业微信通知 3、邮箱通知 4、飞书通知
|
||||
NotificationType: 2
|
||||
|
||||
# 注意点:
|
||||
|
@ -24,12 +26,11 @@ DingTalk:
|
|||
|
||||
# 数据库相关配置
|
||||
MySqlDB:
|
||||
# 数据库开关
|
||||
switch: False
|
||||
host:
|
||||
user:
|
||||
user: dev
|
||||
password:
|
||||
db: test_obp_data
|
||||
db:
|
||||
|
||||
|
||||
# 企业通知的相关配置
|
||||
|
@ -39,6 +40,10 @@ WeChat:
|
|||
email:
|
||||
send_user: 1603453211@qq.com
|
||||
email_host: smtp.qq.com
|
||||
stmp_key: rzuabbobadbuhadc
|
||||
stamp_key: rzuabbobadbuhadc
|
||||
# 收件人
|
||||
send_list: 1603453211@qq.com
|
||||
|
||||
# 飞书通知
|
||||
FeiShuTalk:
|
||||
webhook:
|
|
@ -28,23 +28,16 @@ class ConfigHandler:
|
|||
# 项目路径
|
||||
root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
# 测试数据路径
|
||||
date_path = os.path.join(root_path, 'data' + _SLASH + "Merchant" + _SLASH + "UserLogin")
|
||||
|
||||
merchant_data_path = os.path.join(root_path, 'data' + _SLASH)
|
||||
|
||||
# 用例路径
|
||||
case_path = os.path.join(root_path, 'test_case' + _SLASH)
|
||||
# 测试用例数据路径
|
||||
data_path = os.path.join(root_path, 'data' + _SLASH)
|
||||
|
||||
cache_path = os.path.join(root_path, 'Cache' + _SLASH)
|
||||
if not os.path.exists(cache_path):
|
||||
os.mkdir(cache_path)
|
||||
|
||||
case_path = os.path.join(root_path, 'test_case' + _SLASH)
|
||||
|
||||
# 测试报告路径
|
||||
report_path = os.path.join(root_path, 'report')
|
||||
|
||||
json_path = os.path.join(root_path, 'data' + _SLASH + 'data.json')
|
||||
|
||||
log_path = os.path.join(root_path + _SLASH + 'logs')
|
||||
log_path = os.path.join(root_path, 'logs' + _SLASH + 'log.log')
|
||||
|
||||
info_log_path = os.path.join(root_path, 'logs' + _SLASH + 'info.log')
|
||||
|
||||
|
@ -52,23 +45,20 @@ class ConfigHandler:
|
|||
|
||||
warning_log_path = os.path.join(root_path, 'logs' + _SLASH + 'warning.log')
|
||||
|
||||
if not os.path.exists(report_path):
|
||||
os.mkdir(report_path)
|
||||
config_path = os.path.join(root_path, 'config' + _SLASH + 'config.yaml')
|
||||
|
||||
config_path = os.path.join(root_path, 'config' + _SLASH + 'conf.yaml')
|
||||
file_path = os.path.join(root_path, 'Files' + _SLASH)
|
||||
|
||||
token_yaml_path = os.path.join(root_path, 'data' + _SLASH + 'token.yaml')
|
||||
|
||||
excel_path = os.path.join(root_path, 'data' + _SLASH)
|
||||
# 测试报告路径
|
||||
report_path = os.path.join(root_path, 'report')
|
||||
|
||||
# lib 存放po文件
|
||||
lib_path = os.path.join(root_path, "lib" + _SLASH)
|
||||
|
||||
temp_path = os.path.join(root_path, 'report' + _SLASH + 'tmp')
|
||||
if not os.path.exists(temp_path):
|
||||
os.mkdir(temp_path)
|
||||
html_path = os.path.join(root_path, 'report' + _SLASH + 'html')
|
||||
# temp_path = os.path.join(root_path, 'report' + _SLASH + 'tmp')
|
||||
# if not os.path.exists(temp_path):
|
||||
# os.mkdir(temp_path)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(ConfigHandler.temp_path)
|
||||
print(ConfigHandler.cache_path)
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# 公共参数
|
||||
case_common:
|
||||
allureEpic: 电商平台端
|
||||
allureFeature: 登录模块
|
||||
allureStory: 正常登录
|
||||
|
||||
login:
|
||||
host: ${{host}}
|
||||
url: /api/v1/work/user/loginByPassword
|
||||
method: POST
|
||||
detail: 正常登录
|
||||
headers:
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
# 请求的数据,是 params 还是 json、或者file
|
||||
requestType: json
|
||||
# 是否执行,空或者 true 都会执行
|
||||
is_run: True
|
||||
data:
|
||||
param:
|
||||
phone: '13300000000'
|
||||
password: '123456'
|
||||
# 是否有依赖业务,为空或者false则表示没有
|
||||
dependence_case: False
|
||||
# 依赖的数据
|
||||
dependence_case_data:
|
||||
assert:
|
||||
code:
|
||||
jsonpath: $.code
|
||||
type: ==
|
||||
value: 200
|
||||
AssertType:
|
||||
sql:
|
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2022/3/30 14:56
|
||||
# @Author : 余少琪
|
||||
from utils.readFilesUtils.get_yaml_data_analysis import CaseData
|
||||
from config.setting import ConfigHandler
|
||||
|
||||
TestData = CaseData(ConfigHandler.data_path + r'WorkApplyCenter/sup_apply_list.yaml').case_process()
|
||||
print(TestData)
|
||||
# print([i for i in TestData])
|
||||
is_run = [i['is_run'] for i in TestData]
|
||||
print(is_run)
|
|
@ -0,0 +1,31 @@
|
|||
# 公共参数
|
||||
case_common:
|
||||
allureEpic: 电商平台
|
||||
allureFeature: 文件模块
|
||||
allureStory: PATCH
|
||||
|
||||
batchDisable_01:
|
||||
host: {{host}}
|
||||
url: /adpt/advert/adplan/batchDisable
|
||||
method: PATCH
|
||||
detail: 测试PATCH接口
|
||||
headers:
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
Authorization: work_login_init
|
||||
# 请求的数据,是 params 还是 json、或者file
|
||||
requestType: json
|
||||
# 是否执行,空或者 true 都会执行
|
||||
is_run: Fasle
|
||||
data:
|
||||
|
||||
# 是否有依赖业务,为空或者false则表示没有
|
||||
dependence_case: False
|
||||
# 依赖的数据
|
||||
dependence_case_data:
|
||||
assert:
|
||||
code:
|
||||
jsonpath: $.code
|
||||
type: ==
|
||||
value: 200
|
||||
AssertType:
|
||||
sql:
|
|
@ -0,0 +1,41 @@
|
|||
# 公共参数
|
||||
case_common:
|
||||
allureEpic: 电商平台端
|
||||
allureFeature: 审核中心
|
||||
allureStory: 商品审核
|
||||
|
||||
spu_apply_01:
|
||||
host: ${{host}}
|
||||
url: /api/v1/work/spu/approval/pass
|
||||
method: PUT
|
||||
detail: 正常审核商品(测试一个接口依赖多个数据)
|
||||
headers:
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
token: work_login_init
|
||||
# 请求的数据,是 params 还是 json、或者file
|
||||
requestType: json
|
||||
# 是否执行,空或者 true 都会执行
|
||||
is_run: False
|
||||
data:
|
||||
applyId:
|
||||
reason: 审核时间${{get_time}}
|
||||
# 是否有依赖业务,为空或者false则表示没有
|
||||
dependence_case: True
|
||||
# 依赖的数据
|
||||
dependence_case_data:
|
||||
- case_id: spu_apply_list_01
|
||||
dependent_data:
|
||||
- dependent_type: response
|
||||
jsonpath: $.data.data.[0].applyId
|
||||
replace_key: $.data.applyId
|
||||
- dependent_type: request
|
||||
jsonpath: $.detail
|
||||
replace_key: $.data.reason
|
||||
assert:
|
||||
code:
|
||||
jsonpath: $.code
|
||||
type: ==
|
||||
value: 200
|
||||
AssertType:
|
||||
sql:
|
||||
- select * from test_goods where shop_id = 515
|
|
@ -0,0 +1,34 @@
|
|||
# 公共参数
|
||||
case_common:
|
||||
allureEpic: 电商平台端
|
||||
allureFeature: 审核中心
|
||||
allureStory: 商品审核列表
|
||||
|
||||
|
||||
spu_apply_list_01:
|
||||
host: ${{host}}
|
||||
url: /api/v1/work/spu/approval/spuList
|
||||
method: GET
|
||||
detail: 查看商品审核列表
|
||||
headers:
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
token: work_login_init
|
||||
# 请求的数据,是 params 还是 json、或者file
|
||||
requestType: params
|
||||
# 是否执行,空或者 true 都会执行
|
||||
is_run: False
|
||||
data:
|
||||
spuType: 1
|
||||
pageNum: 1
|
||||
pageSize: 10
|
||||
# 是否有依赖业务,为空或者false则表示没有
|
||||
dependence_case:
|
||||
# 依赖的数据
|
||||
dependence_case_data:
|
||||
assert:
|
||||
code:
|
||||
jsonpath: $.code
|
||||
type: ==
|
||||
value: 200
|
||||
AssertType:
|
||||
sql:
|
|
@ -0,0 +1,42 @@
|
|||
# 公共参数
|
||||
case_common:
|
||||
allureEpic: 电商平台端
|
||||
allureFeature: 审核中心
|
||||
allureStory: 商品审核详情
|
||||
|
||||
spuApplyDetails_01:
|
||||
host: ${{host}}
|
||||
url: /api/v1/work/spu/approval/spuApplyDetails/$url_param{good_id}
|
||||
method: GET
|
||||
detail: 查看商品审核详情
|
||||
headers:
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
token: work_login_init
|
||||
# 请求的数据,是 params 还是 json、或者file\date
|
||||
requestType: json
|
||||
# 是否执行,空或者 true 都会执行
|
||||
is_run: False
|
||||
data:
|
||||
auth:
|
||||
# 是否有依赖业务,为空或者false则表示没有
|
||||
dependence_case: True
|
||||
# 依赖的数据
|
||||
dependence_case_data:
|
||||
- case_id: spu_apply_list_01
|
||||
dependent_data:
|
||||
- dependent_type: response
|
||||
jsonpath: $.data.data.[0].applyId
|
||||
replace_key: $url_param{good_id}
|
||||
- case_id: login_01
|
||||
dependent_data:
|
||||
- dependent_type: response
|
||||
jsonpath: $.data.data.[0].token
|
||||
replace_key: $.data.auth
|
||||
|
||||
assert:
|
||||
code:
|
||||
jsonpath: $.code
|
||||
type: ==
|
||||
value: 200
|
||||
AssertType:
|
||||
sql:
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2021/11/18 23:05
|
||||
# @Time : 2022/3/28 10:49
|
||||
# @Author : 余少琪
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
- # 用例001
|
||||
url: ${{Host}}/recommend/get_head_word
|
||||
method: POST
|
||||
detail: 测试接口
|
||||
headers:
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
requestType: params
|
||||
# 测试平台名称
|
||||
allureEpic: 这里是测试平台名称
|
||||
# 测试模块名称
|
||||
allureFeature: 这里是测试模块名称
|
||||
data:
|
||||
# 请求类型:params 是以url拼接的形式请求,json则传的是json串
|
||||
bid: blog-121903028
|
||||
resp:
|
||||
code:
|
||||
jsonpath: $.status
|
||||
type: ==
|
||||
value: 200
|
||||
AssertType:
|
||||
msg:
|
||||
jsonpath: $.msg
|
||||
type: ==
|
||||
value: 查询成功
|
||||
AssertType:
|
||||
|
||||
sql:
|
|
@ -0,0 +1,36 @@
|
|||
# 公共参数
|
||||
case_common:
|
||||
allureEpic: 婚奢汇
|
||||
allureFeature: 文件上传
|
||||
allureStory: 上传excel文件
|
||||
|
||||
upload_files_02:
|
||||
host: {{host}}
|
||||
url: /adpt/advert/mate/batchUploadMate
|
||||
method: POST
|
||||
detail: 测试上传文件接口
|
||||
headers:
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
Authorization: work_login_ini
|
||||
# 请求的数据,是 params 还是 json、或者file
|
||||
requestType: file
|
||||
# 是否执行,空或者 true 都会执行
|
||||
is_run:
|
||||
data:
|
||||
file:
|
||||
files: test.png
|
||||
# 是否有依赖业务,为空或者false则表示没有
|
||||
data:
|
||||
uids: vc-upload-1649224175138-20
|
||||
params:
|
||||
test: 1
|
||||
dependence_case:
|
||||
# 依赖的数据
|
||||
dependence_case_data:
|
||||
assert:
|
||||
code:
|
||||
jsonpath: $.code
|
||||
type: ==
|
||||
value: 1011006
|
||||
AssertType:
|
||||
sql:
|
|
@ -0,0 +1,32 @@
|
|||
# 公共参数
|
||||
case_common:
|
||||
allureEpic: 婚奢汇
|
||||
allureFeature: 文件上传
|
||||
allureStory: 上传excel文件
|
||||
|
||||
upload_files_01:
|
||||
host: http://parkyz.kkx88.cn
|
||||
url: /api/biz/company/importData
|
||||
method: POST
|
||||
detail: 测试上传文件接口
|
||||
headers:
|
||||
Content-Type: application/json;charset=UTF-8
|
||||
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6IjA1ZTc3ZDRiLWU3NWEtNGMyNi04NjA1LTI4M2Q3ZjdlNWNmZSJ9.2htV4vh5KxR9jEDltfifiwZUPd1OYrwLRXRLM2K1AEgoY-jTCn9z1m5aLPmpIIf2dL5YoSEbyxmGT9Pm1CwzMg
|
||||
# 请求的数据,是 params 还是 json、或者file
|
||||
requestType: file
|
||||
# 是否执行,空或者 true 都会执行
|
||||
is_run:
|
||||
data:
|
||||
file:
|
||||
file: companySewage.xlsx
|
||||
# 是否有依赖业务,为空或者false则表示没有
|
||||
dependence_case: False
|
||||
# 依赖的数据
|
||||
dependence_case_data:
|
||||
assert:
|
||||
code:
|
||||
jsonpath: $.code
|
||||
type: ==
|
||||
value: 401
|
||||
AssertType:
|
||||
sql:
|
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 122 KiB |
After Width: | Height: | Size: 97 KiB |
After Width: | Height: | Size: 148 KiB |
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 182 KiB |
After Width: | Height: | Size: 115 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 150 KiB |
After Width: | Height: | Size: 96 KiB |
After Width: | Height: | Size: 156 KiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 105 KiB |
After Width: | Height: | Size: 119 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 149 KiB |
Before Width: | Height: | Size: 116 KiB |
Before Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 62 KiB |
BIN
images/group.png
Before Width: | Height: | Size: 716 KiB |
BIN
images/img.png
Before Width: | Height: | Size: 67 KiB |
Before Width: | Height: | Size: 123 KiB |
Before Width: | Height: | Size: 204 KiB |
Before Width: | Height: | Size: 140 KiB |
Before Width: | Height: | Size: 154 KiB |
|
@ -1,28 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2022-03-16 13:07:13
|
||||
# @Author : 余少琪
|
||||
|
||||
|
||||
from tools.requestControl import RequestControl
|
||||
from tools.yamlControl import GetCaseData
|
||||
from config.setting import ConfigHandler
|
||||
|
||||
|
||||
class DateDemo(object):
|
||||
@staticmethod
|
||||
def dateDemo(inData):
|
||||
"""
|
||||
测试接口
|
||||
:param inData:
|
||||
:return:
|
||||
"""
|
||||
|
||||
resp = RequestControl().http_request(inData['method'], inData)
|
||||
return resp
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
path = GetCaseData(ConfigHandler.data_path + r'test_demo\DateDemo.yaml').get_yaml_case_data()[0]
|
||||
data = DateDemo().dateDemo(path)
|
||||
print(data)
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2021/11/18 23:05
|
||||
# @Time : 2022/3/28 10:49
|
||||
# @Author : 余少琪
|
|
@ -1,2 +0,0 @@
|
|||
%(levelname)-8s2022-02-21 18:37:52,617 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\error.log:conftest.py:94 执行失败用例数:1
|
||||
%(levelname)-8s2022-02-21 18:38:30,385 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\error.log:conftest.py:94 执行失败用例数:0
|
|
@ -0,0 +1,8 @@
|
|||
%(levelname)-8s2022-04-02 20:11:02,465 C:\work\Study\pytest-auto-api3\logs\error.log:assertControl.py:57 断言失败, 预期值:200, 断言类型==, 实际值1011006
|
||||
%(levelname)-8s2022-04-02 22:38:57,192 C:\work\Study\pytest-auto-api3\logs\error.log:assertControl.py:111 JsonPath值获取失败$.code
|
||||
%(levelname)-8s2022-04-02 22:39:56,756 C:\work\Study\pytest-auto-api3\logs\error.log:assertControl.py:111 JsonPath值获取失败$.code
|
||||
%(levelname)-8s2022-04-02 22:45:55,163 C:\work\Study\pytest-auto-api3\logs\error.log:assertControl.py:115 JsonPath值获取失败$.code
|
||||
%(levelname)-8s2022-04-02 22:46:21,310 C:\work\Study\pytest-auto-api3\logs\error.log:assertControl.py:115 JsonPath值获取失败$.code
|
||||
%(levelname)-8s2022-04-02 23:02:12,628 C:\work\Study\pytest-auto-api3\logs\error.log:assertControl.py:61 断言失败, 预期值:200, 断言类型==, 实际值1011006
|
||||
%(levelname)-8s2022-04-02 23:45:41,734 C:\work\Study\pytest-auto-api3\logs\error.log:assertControl.py:61 断言失败, 预期值:200, 断言类型==, 实际值1011006
|
||||
%(levelname)-8s2022-04-02 23:59:33,188 C:\work\Study\pytest-auto-api3\logs\error.log:assertControl.py:61 断言失败, 预期值:200, 断言类型==, 实际值1011006
|
|
@ -1,45 +0,0 @@
|
|||
%(levelname)-8s2022-02-21 18:37:50,684 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\info.log:run.py:19
|
||||
_ _ _ _____ _
|
||||
__ _ _ __ (_) / \ _ _| |_ __|_ _|__ ___| |_
|
||||
/ _` | '_ \| | / _ \| | | | __/ _ \| |/ _ \/ __| __|
|
||||
| (_| | |_) | |/ ___ \ |_| | || (_) | | __/\__ \ |_
|
||||
\__,_| .__/|_/_/ \_\__,_|\__\___/|_|\___||___/\__|
|
||||
|_|
|
||||
开始执行余少琪的框架项目...
|
||||
|
||||
%(levelname)-8s2022-02-21 18:37:52,389 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\info.log:logDecorator.py:25
|
||||
=================================================================================
|
||||
测试标题: 测试接口
|
||||
请求方式: POST
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8'}
|
||||
请求路径: https://redisdatarecall.csdn.net/recommend/get_head_word
|
||||
请求参数类型: params
|
||||
请求内容: {'bid': 'blog-121903028'}
|
||||
接口响应内容: {'status': 200, 'msg': '查询成功', 'content': ['自动化测试', 'yaml', 'pytest', 'gitee', 'jenkins'], 'error': False}
|
||||
数据库断言数据: {'sql': None}
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-02-21 18:37:52,391 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\info.log:assertControl.py:61 断言成功, 预期值:200, 断言类型==, 实际值200
|
||||
%(levelname)-8s2022-02-21 18:37:52,391 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\info.log:assertControl.py:61 断言成功, 预期值:查询成功, 断言类型==, 实际值查询成功
|
||||
%(levelname)-8s2022-02-21 18:37:52,617 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\info.log:conftest.py:91 执行用例总数: 1
|
||||
%(levelname)-8s2022-02-21 18:37:52,617 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\info.log:conftest.py:92 执行通过用例数:0
|
||||
%(levelname)-8s2022-02-21 18:37:52,620 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\info.log:conftest.py:96 执行异常用例数:0
|
||||
%(levelname)-8s2022-02-21 18:37:52,620 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\info.log:conftest.py:98 执行跳过用例数:0
|
||||
%(levelname)-8s2022-02-21 18:37:52,621 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\info.log:conftest.py:100 执行成功率: 成功率:0.00%
|
||||
%(levelname)-8s2022-02-21 18:38:30,375 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\info.log:logDecorator.py:25
|
||||
=================================================================================
|
||||
测试标题: 测试接口
|
||||
请求方式: POST
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8'}
|
||||
请求路径: https://redisdatarecall.csdn.net/recommend/get_head_word
|
||||
请求参数类型: params
|
||||
请求内容: {'bid': 'blog-121903028'}
|
||||
接口响应内容: {'status': 200, 'msg': '查询成功', 'content': ['自动化测试', 'yaml', 'pytest', 'gitee', 'jenkins'], 'error': False}
|
||||
数据库断言数据: {'sql': None}
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-02-21 18:38:30,377 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\info.log:assertControl.py:61 断言成功, 预期值:200, 断言类型==, 实际值200
|
||||
%(levelname)-8s2022-02-21 18:38:30,378 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\info.log:assertControl.py:61 断言成功, 预期值:查询成功, 断言类型==, 实际值查询成功
|
||||
%(levelname)-8s2022-02-21 18:38:30,384 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\info.log:conftest.py:91 执行用例总数: 1
|
||||
%(levelname)-8s2022-02-21 18:38:30,384 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\info.log:conftest.py:92 执行通过用例数:1
|
||||
%(levelname)-8s2022-02-21 18:38:30,385 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\info.log:conftest.py:96 执行异常用例数:0
|
||||
%(levelname)-8s2022-02-21 18:38:30,386 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\info.log:conftest.py:98 执行跳过用例数:0
|
||||
%(levelname)-8s2022-02-21 18:38:30,386 C:\Users\hzxy\PycharmProjects\py_auto_demo\logs\info.log:conftest.py:100 执行成功率: 成功率:100.00%
|
|
@ -0,0 +1,237 @@
|
|||
%(levelname)-8s2022-04-02 22:48:54,293 C:\work\Study\pytest-auto-api3\logs\warning.log:assertControl.py:118 该用例当前不执行,跳过断言判断
|
||||
%(levelname)-8s2022-04-02 22:56:48,119 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.测试标题: 查看商品审核列表
|
||||
请求方式: GET
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8', 'token': '753263e5f81e3b40436d8b7ceffcdf791c5c'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/spu/approval/spuList
|
||||
请求内容: {'spuType': 1, 'pageNum': 1, 'pageSize': 10}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: {'res': False}
|
||||
数据库断言数据: {'sql': False}
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-02 22:57:31,857 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.测试标题: 查看商品审核列表
|
||||
请求方式: GET
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8', 'token': '7532109233fa72ad486c97e471d6ff2d6204'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/spu/approval/spuList
|
||||
请求内容: {'spuType': 1, 'pageNum': 1, 'pageSize': 10}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: {'res': False}
|
||||
数据库断言数据: {'sql': False}
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-02 22:59:47,978 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.测试标题: 查看商品审核列表
|
||||
请求方式: GET
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8', 'token': '7532b925b258a4c54a7a97e24f668727d0d5'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/spu/approval/spuList
|
||||
请求内容: {'spuType': 1, 'pageNum': 1, 'pageSize': 10}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: False
|
||||
数据库断言数据: False
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-02 23:00:16,779 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.测试标题: 正常登录
|
||||
请求方式: POST
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/user/loginByPassword
|
||||
请求内容: {'param': {'phone': '13300000000', 'password': '123456'}}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: False
|
||||
数据库断言数据: False
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-02 23:01:45,748 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.测试标题: 正常登录
|
||||
请求方式: POST
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/user/loginByPassword
|
||||
请求内容: {'param': {'phone': '13300000000', 'password': '123456'}}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: False
|
||||
数据库断言数据: False
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-02 23:01:45,748 C:\work\Study\pytest-auto-api3\logs\warning.log:conftest.py:61 登录用例设置的是不执行,无法获取到token信息
|
||||
%(levelname)-8s2022-04-02 23:01:46,083 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.测试标题: 查看商品审核列表
|
||||
请求方式: GET
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8', 'token': '7532b925b258a4c54a7a97e24f668727d0d5'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/spu/approval/spuList
|
||||
请求内容: {'spuType': 1, 'pageNum': 1, 'pageSize': 10}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: False
|
||||
数据库断言数据: False
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-02 23:02:12,204 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.测试标题: 正常登录
|
||||
请求方式: POST
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/user/loginByPassword
|
||||
请求内容: {'param': {'phone': '13300000000', 'password': '123456'}}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: False
|
||||
数据库断言数据: False
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-02 23:02:12,205 C:\work\Study\pytest-auto-api3\logs\warning.log:conftest.py:61 登录用例设置的是不执行,无法获取到token信息
|
||||
%(levelname)-8s2022-04-02 23:02:12,817 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.测试标题: 查看商品审核列表
|
||||
请求方式: GET
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8', 'token': '7532b925b258a4c54a7a97e24f668727d0d5'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/spu/approval/spuList
|
||||
请求内容: {'spuType': 1, 'pageNum': 1, 'pageSize': 10}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: False
|
||||
数据库断言数据: False
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-02 23:02:12,840 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.测试标题: 查看商品审核列表
|
||||
请求方式: GET
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8', 'token': '7532b925b258a4c54a7a97e24f668727d0d5'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/spu/approval/spuList
|
||||
请求内容: {'spuType': 1, 'pageNum': 1, 'pageSize': 10}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: False
|
||||
数据库断言数据: False
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-02 23:02:12,847 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.测试标题: 查看商品审核列表
|
||||
请求方式: GET
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8', 'token': '7532b925b258a4c54a7a97e24f668727d0d5'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/spu/approval/spuList
|
||||
请求内容: {'spuType': 1, 'pageNum': 1, 'pageSize': 10}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: False
|
||||
数据库断言数据: False
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-02 23:45:41,234 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.
|
||||
测试标题: 正常登录
|
||||
请求方式: POST
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/user/loginByPassword
|
||||
请求内容: {'param': {'phone': '13300000000', 'password': '123456'}}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: False
|
||||
数据库断言数据: False
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-02 23:45:41,235 C:\work\Study\pytest-auto-api3\logs\warning.log:conftest.py:61 登录用例设置的是不执行,无法获取到token信息
|
||||
%(levelname)-8s2022-04-02 23:45:41,626 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.
|
||||
测试标题: 查看商品审核列表
|
||||
请求方式: GET
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8', 'token': '7532b925b258a4c54a7a97e24f668727d0d5'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/spu/approval/spuList
|
||||
请求内容: {'spuType': 1, 'pageNum': 1, 'pageSize': 10}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: False
|
||||
数据库断言数据: False
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-02 23:45:41,645 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.
|
||||
测试标题: 查看商品审核列表
|
||||
请求方式: GET
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8', 'token': '7532b925b258a4c54a7a97e24f668727d0d5'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/spu/approval/spuList
|
||||
请求内容: {'spuType': 1, 'pageNum': 1, 'pageSize': 10}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: False
|
||||
数据库断言数据: False
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-02 23:45:41,970 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.
|
||||
测试标题: 查看商品审核列表
|
||||
请求方式: GET
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8', 'token': '7532b925b258a4c54a7a97e24f668727d0d5'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/spu/approval/spuList
|
||||
请求内容: {'spuType': 1, 'pageNum': 1, 'pageSize': 10}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: False
|
||||
数据库断言数据: False
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-02 23:59:32,711 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.
|
||||
测试标题: 正常登录
|
||||
请求方式: POST
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/user/loginByPassword
|
||||
请求内容: {'param': {'phone': '13300000000', 'password': '123456'}}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: False
|
||||
数据库断言数据: False
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-02 23:59:32,711 C:\work\Study\pytest-auto-api3\logs\warning.log:conftest.py:61 登录用例设置的是不执行,无法获取到token信息
|
||||
%(levelname)-8s2022-04-02 23:59:32,711 C:\work\Study\pytest-auto-api3\logs\warning.log:conftest.py:61 登录用例设置的是不执行,无法获取到token信息
|
||||
%(levelname)-8s2022-04-02 23:59:32,714 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.
|
||||
测试标题: 正常登录
|
||||
请求方式: POST
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/user/loginByPassword
|
||||
请求内容: {'param': {'phone': '13300000000', 'password': '123456'}}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: False
|
||||
数据库断言数据: False
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-02 23:59:32,715 C:\work\Study\pytest-auto-api3\logs\warning.log:conftest.py:61 登录用例设置的是不执行,无法获取到token信息
|
||||
%(levelname)-8s2022-04-02 23:59:33,111 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.
|
||||
测试标题: 查看商品审核列表
|
||||
请求方式: GET
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8', 'token': '7532b925b258a4c54a7a97e24f668727d0d5'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/spu/approval/spuList
|
||||
请求内容: {'spuType': 1, 'pageNum': 1, 'pageSize': 10}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: False
|
||||
数据库断言数据: False
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-02 23:59:33,116 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.
|
||||
测试标题: 查看商品审核列表
|
||||
请求方式: GET
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8', 'token': '7532b925b258a4c54a7a97e24f668727d0d5'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/spu/approval/spuList
|
||||
请求内容: {'spuType': 1, 'pageNum': 1, 'pageSize': 10}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: False
|
||||
数据库断言数据: False
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-02 23:59:33,410 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.
|
||||
测试标题: 查看商品审核列表
|
||||
请求方式: GET
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8', 'token': '7532b925b258a4c54a7a97e24f668727d0d5'}
|
||||
请求路径: http://work.test.feng-go.com/api/v1/work/spu/approval/spuList
|
||||
请求内容: {'spuType': 1, 'pageNum': 1, 'pageSize': 10}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: False
|
||||
数据库断言数据: False
|
||||
=================================================================================
|
||||
%(levelname)-8s2022-04-03 00:00:28,088 C:\work\Study\pytest-auto-api3\logs\warning.log:logDecoratorl.py:51
|
||||
=================================================================================
|
||||
该条用例跳过执行.
|
||||
测试标题: 测试patch请求方式
|
||||
请求方式: PATCH
|
||||
请求头: {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': 'Bearer eyJhbGciOiJIUzUxMiJ9.eyJ1c2VySWQiOjEyNjU0NzY4OTA2NzI2NzI4MDgsImFjY291bnQiOiJzdXBlckFkbWluIiwidXVpZCI6IjJiOTNlNTNjLWRkM2QtNGM0MS05YjI2LTA1Y2NhM2JjMjNlOSIsInN1YiI6IjEyNjU0NzY4OTA2NzI2NzI4MDgiLCJpYXQiOjE2NDg2ODg2NTgsImV4cCI6MTY0ODc3NTA1OH0.640mDK2Eyid_KjSi0Ijei6VW6LYQZ7oYfGCgq4ajqehACzqfvaG4XJ5lqizRSVhidl7J1XTJZeBYVCjEe0GMdw'}
|
||||
请求路径: http://39.105.186.77:8082/adpt/advert/adplan/batchDisable
|
||||
请求内容: {'ids': ['1509343309343780875']}
|
||||
依赖测试用例: 暂无依赖用例数据
|
||||
接口响应内容: False
|
||||
数据库断言数据: False
|
||||
=================================================================================
|
|
@ -1,4 +1,9 @@
|
|||
[pytest]
|
||||
addopts = -p no:warnings
|
||||
testpaths = test_case/
|
||||
python_files = test_*.py
|
||||
python_classes = Test*
|
||||
python_function = test_*
|
||||
|
||||
markers =
|
||||
shop: project_shop
|
||||
shop_list: project_shop_list
|
||||
smoke: 冒烟测试
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
<environment>
|
||||
<parameter>
|
||||
<key>测试平台</key>
|
||||
<value>测试项目</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<key>测试环境</key>
|
||||
<value>TEST</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<key>测试人员</key>
|
||||
<value>余少琪</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<key>邮箱</key>
|
||||
<value>1603453211@qq.com</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<key>python.Version</key>
|
||||
<value>3.9.0</value>
|
||||
</parameter>
|
||||
</environment>
|
52
run.py
|
@ -1,23 +1,23 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2021/11/26 23:12
|
||||
# @Time : 2022/3/29 15:01
|
||||
# @Author : 余少琪
|
||||
import traceback
|
||||
|
||||
import pytest
|
||||
import os
|
||||
from tools.logControl import INFO
|
||||
from tools.yamlControl import GetYamlData
|
||||
from config.setting import ConfigHandler
|
||||
from tools import getNotificationType
|
||||
from tools.weChatSendControl import WeChatSend
|
||||
from tools.dingtalkControl import DingTalkSendMsg
|
||||
from tools.sendmailControl import SendEmail
|
||||
import traceback
|
||||
import pytest
|
||||
from utils import project_name
|
||||
from utils.logUtils.logControl import INFO
|
||||
from utils import get_notification_type
|
||||
from utils.noticUtils.weChatSendControl import WeChatSend
|
||||
from utils.noticUtils.dingtalkControl import DingTalkSendMsg
|
||||
from utils.noticUtils.sendmailControl import SendEmail
|
||||
from Enums.notificationType_enum import NotificationType
|
||||
from utils.noticUtils.feishuControl import FeiShuTalkChatBot
|
||||
|
||||
|
||||
def run():
|
||||
# 从配置文件中获取项目名称
|
||||
project_name = GetYamlData(ConfigHandler.config_path).get_yaml_data()['ProjectName'][0]
|
||||
try:
|
||||
INFO.logger.info(
|
||||
"""
|
||||
|
@ -30,15 +30,33 @@ def run():
|
|||
开始执行{}项目...
|
||||
""".format(project_name)
|
||||
)
|
||||
pytest.main(['-s', '-W', 'ignore:Module already imported:pytest.PytestWarning', '--alluredir', './report/tmp'])
|
||||
|
||||
pytest.main(['-s', '-W', 'ignore:Module already imported:pytest.PytestWarning',
|
||||
'--alluredir', './report/tmp'])
|
||||
"""
|
||||
--reruns: 失败重跑次数
|
||||
--count: 重复执行次数
|
||||
-v: 显示错误位置以及错误的详细信息
|
||||
-s: 等价于 pytest --capture=no 可以捕获print函数的输出
|
||||
-q: 简化输出信息
|
||||
-m: 运行指定标签的测试用例
|
||||
-x: 一旦错误,则停止运行
|
||||
--maxfail: 设置最大失败次数,当超出这个阈值时,则不会在执行测试用例
|
||||
"--reruns=3", "--reruns-delay=2"
|
||||
"""
|
||||
|
||||
os.system(r"allure generate ./report/tmp -o ./report/html --clean")
|
||||
# 通过配置文件判断发送报告通知类型:1:钉钉 2:企业微信通知 3、邮箱
|
||||
if getNotificationType() == 1:
|
||||
# 判断通知类型
|
||||
if get_notification_type() == NotificationType.DEFAULT.value:
|
||||
pass
|
||||
elif get_notification_type() == NotificationType.DING_TALK.value:
|
||||
DingTalkSendMsg().send_ding_notification()
|
||||
elif getNotificationType() == 2:
|
||||
WeChatSend().send_email_notification()
|
||||
elif getNotificationType() == 3:
|
||||
elif get_notification_type() == NotificationType.WECHAT.value:
|
||||
WeChatSend().send_wechat_notification()
|
||||
elif get_notification_type() == NotificationType.EMAIL.value:
|
||||
SendEmail().send_main()
|
||||
elif get_notification_type() == NotificationType.FEI_SHU.value:
|
||||
FeiShuTalkChatBot().post()
|
||||
else:
|
||||
raise ValueError("通知类型配置错误,暂不支持该类型通知")
|
||||
os.system(f"allure serve ./report/tmp -p 9999")
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2022-04-07 21:03:43
|
||||
# @Author : 余少琪
|
||||
|
||||
|
||||
import allure
|
||||
import pytest
|
||||
from config.setting import ConfigHandler
|
||||
from utils.readFilesUtils.get_yaml_data_analysis import CaseData
|
||||
from utils.assertUtils.assertControl import Assert
|
||||
from utils.requestsUtils.requestControl import RequestControl
|
||||
|
||||
|
||||
TestData = CaseData(ConfigHandler.data_path + r'Login/login.yaml').case_process()
|
||||
|
||||
|
||||
@allure.epic("电商平台端")
|
||||
@allure.feature("登录模块")
|
||||
class TestLogin:
|
||||
|
||||
@allure.story("正常登录")
|
||||
@pytest.mark.parametrize('in_data', TestData, ids=[i['detail'] for i in TestData])
|
||||
def test_login(self, in_data, case_skip):
|
||||
"""
|
||||
:param :
|
||||
:return:
|
||||
"""
|
||||
|
||||
res = RequestControl().http_request(in_data)
|
||||
Assert(in_data['assert']).assert_equality(response_data=res[0], sql_data=res[1])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main(['test_login.py', '-s', '-W', 'ignore:Module already imported:pytest.PytestWarning'])
|
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2022-04-07 21:03:43
|
||||
# @Author : 余少琪
|
||||
|
||||
|
||||
import allure
|
||||
import pytest
|
||||
from config.setting import ConfigHandler
|
||||
from utils.readFilesUtils.get_yaml_data_analysis import CaseData
|
||||
from utils.assertUtils.assertControl import Assert
|
||||
from utils.requestsUtils.requestControl import RequestControl
|
||||
|
||||
|
||||
TestData = CaseData(ConfigHandler.data_path + r'uplpad_file_test/batchDisable.yaml').case_process()
|
||||
|
||||
|
||||
@allure.epic("换社会")
|
||||
@allure.feature("登录模块")
|
||||
class TestBatchdisable:
|
||||
|
||||
@allure.story("测试patch请求方式")
|
||||
@pytest.mark.parametrize('in_data', TestData, ids=[i['detail'] for i in TestData])
|
||||
def test_batchDisable(self, in_data, case_skip):
|
||||
"""
|
||||
:param :
|
||||
:return:
|
||||
"""
|
||||
|
||||
res = RequestControl().http_request(in_data)
|
||||
Assert(in_data['assert']).assert_equality(response_data=res[0], sql_data=res[1])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main(['test_batchDisable.py', '-s', '-W', 'ignore:Module already imported:pytest.PytestWarning'])
|
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2022-04-07 21:03:43
|
||||
# @Author : 余少琪
|
||||
|
||||
|
||||
import allure
|
||||
import pytest
|
||||
from config.setting import ConfigHandler
|
||||
from utils.readFilesUtils.get_yaml_data_analysis import CaseData
|
||||
from utils.assertUtils.assertControl import Assert
|
||||
from utils.requestsUtils.requestControl import RequestControl
|
||||
|
||||
|
||||
TestData = CaseData(ConfigHandler.data_path + r'WorkApplyCenter/spu_apply.yaml').case_process()
|
||||
|
||||
|
||||
@allure.epic("电商平台端")
|
||||
@allure.feature("审核中心")
|
||||
class TestSpuApply:
|
||||
|
||||
@allure.story("商品审核")
|
||||
@pytest.mark.parametrize('in_data', TestData, ids=[i['detail'] for i in TestData])
|
||||
def test_spu_apply(self, in_data, case_skip):
|
||||
"""
|
||||
:param :
|
||||
:return:
|
||||
"""
|
||||
|
||||
res = RequestControl().http_request(in_data)
|
||||
Assert(in_data['assert']).assert_equality(response_data=res[0], sql_data=res[1])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main(['test_spu_apply.py', '-s', '-W', 'ignore:Module already imported:pytest.PytestWarning'])
|
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2022-04-07 21:03:43
|
||||
# @Author : 余少琪
|
||||
|
||||
|
||||
import allure
|
||||
import pytest
|
||||
from config.setting import ConfigHandler
|
||||
from utils.readFilesUtils.get_yaml_data_analysis import CaseData
|
||||
from utils.assertUtils.assertControl import Assert
|
||||
from utils.requestsUtils.requestControl import RequestControl
|
||||
|
||||
|
||||
TestData = CaseData(ConfigHandler.data_path + r'WorkApplyCenter/sup_apply_list.yaml').case_process()
|
||||
|
||||
|
||||
@allure.epic("电商平台端")
|
||||
@allure.feature("审核中心")
|
||||
class TestSupApplyList:
|
||||
|
||||
@allure.story("商品审核列表")
|
||||
@pytest.mark.parametrize('in_data', TestData, ids=[i['detail'] for i in TestData])
|
||||
def test_sup_apply_list(self, in_data, case_skip):
|
||||
"""
|
||||
:param :
|
||||
:return:
|
||||
"""
|
||||
|
||||
res = RequestControl().http_request(in_data)
|
||||
Assert(in_data['assert']).assert_equality(response_data=res[0], sql_data=res[1])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main(['test_sup_apply_list.py', '-s', '-W', 'ignore:Module already imported:pytest.PytestWarning'])
|
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2022-04-07 21:03:43
|
||||
# @Author : 余少琪
|
||||
|
||||
|
||||
import allure
|
||||
import pytest
|
||||
from config.setting import ConfigHandler
|
||||
from utils.readFilesUtils.get_yaml_data_analysis import CaseData
|
||||
from utils.assertUtils.assertControl import Assert
|
||||
from utils.requestsUtils.requestControl import RequestControl
|
||||
|
||||
|
||||
TestData = CaseData(ConfigHandler.data_path + r'WorkApplyCenter/work_apply_good_detail.yaml').case_process()
|
||||
|
||||
|
||||
@allure.epic("电商平台端")
|
||||
@allure.feature("审核中心")
|
||||
class TestWorkApplyGoodDetail:
|
||||
|
||||
@allure.story("商品审核详情")
|
||||
@pytest.mark.parametrize('in_data', TestData, ids=[i['detail'] for i in TestData])
|
||||
def test_work_apply_good_detail(self, in_data, case_skip):
|
||||
"""
|
||||
:param :
|
||||
:return:
|
||||
"""
|
||||
|
||||
res = RequestControl().http_request(in_data)
|
||||
Assert(in_data['assert']).assert_equality(response_data=res[0], sql_data=res[1])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main(['test_work_apply_good_detail.py', '-s', '-W', 'ignore:Module already imported:pytest.PytestWarning'])
|
|
@ -1,21 +1,26 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2021/11/28 23:05
|
||||
# @Time : 2022/3/30 14:12
|
||||
# @Author : 余少琪
|
||||
import pytest
|
||||
|
||||
import os
|
||||
import pytest
|
||||
import time
|
||||
import allure
|
||||
from utils.requestsUtils.requestControl import RequestControl
|
||||
from config.setting import ConfigHandler
|
||||
from tools.yamlControl import GetYamlData
|
||||
|
||||
|
||||
_PROJECT_NAME = GetYamlData(ConfigHandler.config_path).get_yaml_data()['ProjectName'][0]
|
||||
_TEST_NAME = GetYamlData(ConfigHandler.config_path).get_yaml_data()['TestName']
|
||||
from utils.readFilesUtils.get_yaml_data_analysis import CaseData
|
||||
from utils.cacheUtils.cacheControl import Cache
|
||||
from utils.readFilesUtils.get_all_files_path import get_all_files
|
||||
from utils.logUtils.logControl import WARNING, INFO, ERROR
|
||||
from Enums.yamlData_enum import YAMLDate
|
||||
from utils.otherUtils.allureDate.allure_tools import allure_step, allure_step_no
|
||||
|
||||
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
def clear_report():
|
||||
try:
|
||||
for one in os.listdir(ConfigHandler.report_path + f'/tmp'):
|
||||
for one in os.listdir(ConfigHandler.report_path + '/tmp'):
|
||||
if 'json' in one:
|
||||
os.remove(ConfigHandler.report_path + f'/tmp/{one}')
|
||||
if 'txt' in one:
|
||||
|
@ -26,3 +31,101 @@ def clear_report():
|
|||
yield
|
||||
|
||||
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
def write_case_process():
|
||||
"""
|
||||
获取所有用例,写入用例池中
|
||||
:return:
|
||||
"""
|
||||
case_data = {}
|
||||
# 循环拿到所有存放用例的文件路径
|
||||
for i in get_all_files(ConfigHandler.data_path):
|
||||
# 循环读取文件中的数据
|
||||
case_process = CaseData(i).case_process(case_id_switch=True)
|
||||
# 转换数据类型
|
||||
for case in case_process:
|
||||
for k, v in case.items():
|
||||
# 判断 case_id 是否已存在
|
||||
case_id_exit = k in case_data.keys()
|
||||
# 如果case_id 不存在,则将用例写入缓存池中
|
||||
if case_id_exit is False:
|
||||
case_data[k] = v
|
||||
# 当 case_id 为 True 存在时,则跑出异常
|
||||
elif case_id_exit is True:
|
||||
raise ValueError(f"case_id: {k} 存在重复项, 请修改case_id\n"
|
||||
f"文件路径: {i}")
|
||||
|
||||
Cache('case_process').set_caches(case_data)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
def work_login_init():
|
||||
"""
|
||||
获取平台端的token信息
|
||||
:return:
|
||||
"""
|
||||
login_yaml = CaseData(ConfigHandler.data_path + 'Login/login.yaml').case_process()[0]
|
||||
res = RequestControl().http_request(login_yaml)
|
||||
# 将token写入缓存中
|
||||
if res[0] is not False:
|
||||
token = res[0]['data']['token']
|
||||
Cache('work_login_init').set_caches(token)
|
||||
return token
|
||||
else:
|
||||
WARNING.logger.warning("登录用例设置的是不执行,无法获取到token信息")
|
||||
|
||||
|
||||
def pytest_collection_modifyitems(items):
|
||||
"""
|
||||
测试用例收集完成时,将收集到的 item 的 name 和 node_id 的中文显示在控制台上
|
||||
:return:
|
||||
"""
|
||||
for item in items:
|
||||
item.name = item.name.encode("utf-8").decode("unicode_escape")
|
||||
item._nodeid = item.nodeid.encode("utf-8").decode("unicode_escape")
|
||||
|
||||
|
||||
# 定义单个标签
|
||||
def pytest_configure(config):
|
||||
config.addinivalue_line(
|
||||
"markers", "smoke"
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function", autouse=True)
|
||||
def case_skip(in_data):
|
||||
"""处理跳过用例"""
|
||||
if in_data['is_run'] is False:
|
||||
allure.dynamic.title(in_data[YAMLDate.DETAIL.value])
|
||||
allure_step_no(f"请求URL: {in_data[YAMLDate.IS_RUN.value]}")
|
||||
allure_step_no(f"请求方式: {in_data[YAMLDate.METHOD.value]}")
|
||||
allure_step("请求头: ", in_data[YAMLDate.HEADER.value])
|
||||
allure_step("请求数据: ", in_data[YAMLDate.DATA.value])
|
||||
allure_step("依赖数据: ", in_data[YAMLDate.DEPENDENCE_CASE_DATA.value])
|
||||
allure_step("预期数据: ", in_data[YAMLDate.ASSERT.value])
|
||||
pytest.skip()
|
||||
|
||||
|
||||
def pytest_terminal_summary(terminalreporter):
|
||||
"""
|
||||
收集测试结果
|
||||
"""
|
||||
|
||||
_PASSED = len([i for i in terminalreporter.stats.get('passed', []) if i.when != 'teardown'])
|
||||
_ERROR = len([i for i in terminalreporter.stats.get('error', []) if i.when != 'teardown'])
|
||||
_FAILED = len([i for i in terminalreporter.stats.get('failed', []) if i.when != 'teardown'])
|
||||
_SKIPPED = len([i for i in terminalreporter.stats.get('skipped', []) if i.when != 'teardown'])
|
||||
_TOTAL = terminalreporter._numcollected
|
||||
_TIMES = time.time() - terminalreporter._sessionstarttime
|
||||
|
||||
INFO.logger.info(f"成功用例数: {_PASSED}")
|
||||
ERROR.logger.error(f"异常用例数: {_ERROR}")
|
||||
ERROR.logger.error(f"失败用例数: {_FAILED}")
|
||||
WARNING.logger.warning(f"跳过用例数: {_SKIPPED}")
|
||||
INFO.logger.info("用例执行时长: %.2f" % _TIMES + " s")
|
||||
|
||||
try:
|
||||
_RATE = round((_PASSED + _SKIPPED) / _TOTAL * 100, 2)
|
||||
INFO.logger.info("用例成功率: %.2f" % _RATE + " %")
|
||||
except ZeroDivisionError:
|
||||
INFO.logger.info("用例成功率: 0.00 %")
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2022-03-16 13:07:13
|
||||
# @Author : 余少琪
|
||||
|
||||
|
||||
import allure
|
||||
import pytest
|
||||
from config.setting import ConfigHandler
|
||||
from tools.yamlControl import GetCaseData
|
||||
from lib.test_demo.DateDemo import DateDemo
|
||||
from tools.assertControl import Assert
|
||||
|
||||
TestData = GetCaseData(ConfigHandler.merchant_data_path + r'test_demo\DateDemo.yaml').get_yaml_case_data()
|
||||
|
||||
|
||||
@allure.epic("这里是测试平台名称")
|
||||
@allure.feature("这里是测试模块名称")
|
||||
class TestDateDemo:
|
||||
|
||||
@allure.story("这是一个测试的demo接口")
|
||||
@pytest.mark.parametrize('data', TestData)
|
||||
def test_date_demo(self, date):
|
||||
"""
|
||||
测试接口
|
||||
:param :
|
||||
:return:
|
||||
"""
|
||||
|
||||
res = DateDemo().dateDemo(date)
|
||||
Assert(date['resp']).assert_equality(response_data=res[0], sql_data=res[1])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main(['test_DateDemo.py', '-s', '-W', 'ignore:Module already imported:pytest.PytestWarning', "--reruns=2",
|
||||
"--reruns-delay=2"])
|
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2022-04-07 21:03:43
|
||||
# @Author : 余少琪
|
||||
|
||||
|
||||
import allure
|
||||
import pytest
|
||||
from config.setting import ConfigHandler
|
||||
from utils.readFilesUtils.get_yaml_data_analysis import CaseData
|
||||
from utils.assertUtils.assertControl import Assert
|
||||
from utils.requestsUtils.requestControl import RequestControl
|
||||
|
||||
|
||||
TestData = CaseData(ConfigHandler.data_path + r'uplpad_file_test/up_files.yaml').case_process()
|
||||
|
||||
|
||||
@allure.epic("婚奢汇")
|
||||
@allure.feature("文件上传")
|
||||
class TestUpFiles:
|
||||
|
||||
@allure.story("上传excel文件")
|
||||
@pytest.mark.parametrize('in_data', TestData, ids=[i['detail'] for i in TestData])
|
||||
def test_up_files(self, in_data, case_skip):
|
||||
"""
|
||||
:param :
|
||||
:return:
|
||||
"""
|
||||
|
||||
res = RequestControl().http_request(in_data)
|
||||
Assert(in_data['assert']).assert_equality(response_data=res[0], sql_data=res[1])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main(['test_up_files.py', '-s', '-W', 'ignore:Module already imported:pytest.PytestWarning'])
|
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2022-04-07 21:03:43
|
||||
# @Author : 余少琪
|
||||
|
||||
|
||||
import allure
|
||||
import pytest
|
||||
from config.setting import ConfigHandler
|
||||
from utils.readFilesUtils.get_yaml_data_analysis import CaseData
|
||||
from utils.assertUtils.assertControl import Assert
|
||||
from utils.requestsUtils.requestControl import RequestControl
|
||||
|
||||
|
||||
TestData = CaseData(ConfigHandler.data_path + r'uplpad_file_test/upload_files.yaml').case_process()
|
||||
|
||||
|
||||
@allure.epic("婚奢汇")
|
||||
@allure.feature("文件上传")
|
||||
class TestUploadFiles:
|
||||
|
||||
@allure.story("上传excel文件")
|
||||
@pytest.mark.parametrize('in_data', TestData, ids=[i['detail'] for i in TestData])
|
||||
def test_upload_files(self, in_data, case_skip):
|
||||
"""
|
||||
:param :
|
||||
:return:
|
||||
"""
|
||||
|
||||
res = RequestControl().http_request(in_data)
|
||||
Assert(in_data['assert']).assert_equality(response_data=res[0], sql_data=res[1])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main(['test_upload_files.py', '-s', '-W', 'ignore:Module already imported:pytest.PytestWarning'])
|
|
@ -1,159 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2021/12/14 22:06
|
||||
# @Author : 余少琪
|
||||
|
||||
import allure
|
||||
import json
|
||||
import datetime
|
||||
from config.setting import get_current_system, ConfigHandler
|
||||
from tools.yamlControl import GetYamlData
|
||||
|
||||
|
||||
def allure_step(step: str, var: str) -> None:
|
||||
"""
|
||||
:param step: 步骤及附件名称
|
||||
:param var: 附件内容
|
||||
"""
|
||||
with allure.step(step):
|
||||
allure.attach(
|
||||
json.dumps(
|
||||
str(var),
|
||||
ensure_ascii=False,
|
||||
indent=4),
|
||||
step,
|
||||
allure.attachment_type.JSON)
|
||||
|
||||
|
||||
def allure_step_no(step: str):
|
||||
"""
|
||||
无附件的操作步骤
|
||||
:param step: 步骤名称
|
||||
:return:
|
||||
"""
|
||||
with allure.step(step):
|
||||
pass
|
||||
|
||||
|
||||
def slash():
|
||||
# 判断系统路径
|
||||
SLASH = '\\'
|
||||
|
||||
# 判断当前操作系统
|
||||
if get_current_system() == 'Linux' or get_current_system() == "Darwin":
|
||||
SLASH = '/'
|
||||
|
||||
return SLASH
|
||||
|
||||
|
||||
def SqlSwitch() -> bool:
|
||||
"""获取数据库开关"""
|
||||
switch = GetYamlData(ConfigHandler.config_path) \
|
||||
.get_yaml_data()['MySqlDB']["switch"]
|
||||
return switch
|
||||
|
||||
|
||||
def getNotificationType():
|
||||
# 获取报告通知类型,是发送钉钉还是企业邮箱
|
||||
Date = GetYamlData(ConfigHandler.config_path).get_yaml_data()['NotificationType']
|
||||
return Date
|
||||
|
||||
|
||||
def writePageFiles(classTitle, funcTitle, caseDetail, casePath, yamlPath):
|
||||
"""
|
||||
自动写成 py 文件
|
||||
:param yamlPath:
|
||||
:param casePath: 生成的py文件地址
|
||||
:param classTitle: 类名称, 读取用例中的 caseTitle 作为类名称
|
||||
:param funcTitle: 函数名称 caseTitle,首字母小写
|
||||
:param caseDetail: 函数描述,读取用例中的描述内容,做为函数描述
|
||||
:return:
|
||||
"""
|
||||
Author = GetYamlData(ConfigHandler.config_path).get_yaml_data()['TestName']
|
||||
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
page = f'''#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : {now}
|
||||
# @Author : {Author}
|
||||
|
||||
|
||||
from tools.requestControl import RequestControl
|
||||
from tools.yamlControl import GetCaseData
|
||||
from config.setting import ConfigHandler
|
||||
|
||||
|
||||
class {classTitle}(object):
|
||||
@staticmethod
|
||||
def {funcTitle}(inData):
|
||||
"""
|
||||
{caseDetail}
|
||||
:param inData:
|
||||
:return:
|
||||
"""
|
||||
|
||||
resp = RequestControl().HttpRequest(inData['method'], inData)
|
||||
return resp
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
path = GetCaseData(ConfigHandler.data_path + r'{yamlPath}').get_yaml_case_data()[0]
|
||||
data = {classTitle}().{funcTitle}(path)
|
||||
print(data)
|
||||
'''
|
||||
with open(casePath, 'w', encoding="utf-8") as f:
|
||||
f.write(page)
|
||||
|
||||
|
||||
def writeTestCaseFile(allureEpic, allureFeature, classTitle, funcTitle, caseDetail, casePath, yamlPath, fileName, PackagePath):
|
||||
"""
|
||||
|
||||
:param allureEpic: 项目名称
|
||||
:param allureFeature: 模块名称
|
||||
:param classTitle: 类名称
|
||||
:param funcTitle: 函数名称
|
||||
:param caseDetail: 用例描述
|
||||
:param casePath: case 路径
|
||||
:param yamlPath: yaml 文件路径
|
||||
:return:
|
||||
"""
|
||||
Author = GetYamlData(ConfigHandler.config_path).get_yaml_data()['TestName']
|
||||
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
page = f'''#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : {now}
|
||||
# @Author : {Author}
|
||||
|
||||
|
||||
import allure
|
||||
import pytest
|
||||
from config.setting import ConfigHandler
|
||||
from tools.yamlControl import GetCaseData
|
||||
{PackagePath}
|
||||
from tools.assertControl import Assert
|
||||
|
||||
TestData = GetCaseData(ConfigHandler.merchant_data_path + r'{yamlPath}').get_yaml_case_data()
|
||||
|
||||
|
||||
@allure.epic("{allureEpic}")
|
||||
@allure.feature("{allureFeature}")
|
||||
class Test{classTitle}:
|
||||
|
||||
@allure.story("这是一个测试的demo接口")
|
||||
@pytest.mark.parametrize('inData', TestData)
|
||||
def test_{funcTitle}(self, inData):
|
||||
"""
|
||||
{caseDetail}
|
||||
:param :
|
||||
:return:
|
||||
"""
|
||||
|
||||
res = {classTitle}().{funcTitle}(inData)
|
||||
Assert(inData['resp']).assertEquality(responseData=res[0], sqlData=res[1])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main(['{fileName}', '-s', '-W', 'ignore:Module already imported:pytest.PytestWarning', "--reruns=2", "--reruns-delay=2"])
|
||||
'''
|
||||
with open(casePath, 'w', encoding="utf-8") as f:
|
||||
f.write(page)
|