705 lines
34 KiB
Markdown
705 lines
34 KiB
Markdown
## 前言
|
||
|
||
公司突然要求你做自动化,但是没有代码基础不知道怎么做?或者有自动化基础,但是不知道如何系统性的做自动化, 放在yaml文件中维护,不知道如何处理多业务依赖的逻辑?
|
||
|
||
那么本自动化框架,将为你解决这些问题。
|
||
- 框架主要使用 python 语言编写,结合 pytest 进行二次开发,用户仅需要在 yaml 文件中编写测试用例, 编写成功之后,会自动生成测试用例代码。
|
||
- 如果是具备代码基础的,也可以直接通过 py 文件编写测试用例。
|
||
- 使用 Allure 生成报告,并针对测试报告样式进行了调整,使得报告更加美观;
|
||
- 测试完成后,支持发送 企业微信通知/ 钉钉通知/ 邮箱通知,灵活配置。
|
||
- 使用GitLink个人建站服务部署Allure在线测试报告,随时随地查看测试报告。
|
||
|
||
|
||
## 一、框架介绍
|
||
|
||
本框架主要是基于 Python + Pytest + Allure + Loguru + 邮件通知/企业微信通知/钉钉通知 实现的接口自动化框架。
|
||
|
||
* git地址: [https://www.gitlink.org.cn/kytest/apiautotest.git](https://www.gitlink.org.cn/floraachy/apiautotest)
|
||
* 项目参与者: floraachy
|
||
* 个人主页: [https://www.gitlink.org.cn/floraachy](https://www.gitlink.org.cn/floraachy)
|
||
* 测试社区地址: [https://www.gitlink.org.cn/zone/tester](https://www.gitlink.org.cn/zone/tester)
|
||
|
||
<img src="https://www.gitlink.org.cn//api/attachments/ca4845c4-9bdd-4485-9f68-14352520a757" alt="加入我们" style="width: 300px; height: 350px;">
|
||
|
||
|
||
如果对您有帮助,请点亮 小星星 以表支持,谢谢!
|
||
对于框架有任何问题,请先仔细阅读本文~ 如果还有不了解的,欢迎联系我!
|
||
|
||
|
||
## 二、实现功能
|
||
|
||
* 通过session会话方式,解决了登录之后cookie关联处理`
|
||
* 动态多断言: 如接口需要同时校验响应数据和sql校验,支持多场景断言
|
||
* 支持单独调试用例,支持用例的重复执行
|
||
* 框架天然支持接口动态传参、关联灵活处理
|
||
* 支持测试数据分析,测试数据不符合规范有预警机制
|
||
* 支持通过用例数据动态配置pytest.mark, 包括自定义标记,pytest.mark.skip以及pytest.mark.usefixtures
|
||
* 支持利用allure设置用例优先级,运行指定优先级的用例
|
||
* 执行环境一键切换,解决多环境相互影响问题
|
||
* 自动生成用例代码: 测试人员在yaml/excel文件中填写好测试用例, 程序可以直接生成用例代码,纯小白也能使用
|
||
* 支持参数多类型提取:支持从响应数据,数据库,用例数据中通过jsonpath或者正则方式提取数据
|
||
* 使用Allure生成测试报告,并对测试报告进行了定制化修改,使得测试报告更加美观
|
||
* 日志模块: 采用loguru管理日志,可以输出更为优雅,简洁的日志
|
||
* 钉钉、企业微信通知: 支持多种通知场景,执行成功之后,可选择发送钉钉、或者企业微信、邮箱通知
|
||
* 使用pipenv管理虚拟环境和依赖文件,提供了一系列命令和选项来帮助你实现各种依赖和环境管理相关的操作
|
||
* 支持将swagger.json接口文档转为YAML用例
|
||
* 支持接口相应后添加等待时间,方便接口调用后,进行一系列数据初始化操作,待操作成功后,执行后续接口
|
||
|
||
|
||
|
||
## 三、依赖库
|
||
```
|
||
allure_python_commons==2.9.45
|
||
click==8.1.7
|
||
Faker==21.0.0
|
||
jsonpath==0.82.2
|
||
loguru==0.7.2
|
||
openpyxl==3.1.2
|
||
pydantic==2.7.1
|
||
PyMySQL==1.1.0
|
||
pytest==8.0.2 Pytest 8.2.0 和 8.1.0 的几个版本会破坏 allure 的 listener 导致执行报错,也就是版本不兼容,需把pytest 回退到8.0.2就不报错啦!
|
||
PyYAML==6.0.1
|
||
PyYAML==6.0.1
|
||
Requests==2.31.0
|
||
requests_toolbelt==1.0.0
|
||
ruamel.base==1.0.0
|
||
sshtunnel==0.4.0
|
||
xpinyin==0.7.6
|
||
yagmail==0.15.293
|
||
|
||
```
|
||
|
||
|
||
## 四、安装教程
|
||
|
||
1. 通过Git工具clone代码到本地 或者 直接下载压缩包ZIP
|
||
```
|
||
https://gitlink.org.cn/floraachy/apiautotest.git
|
||
```
|
||
|
||
2. 本地电脑搭建好 python环境,我使用的python版本是3.9。包括allure测试报告所需的java环境(安装jdk)。
|
||
|
||
3. 安装依赖包
|
||
方法一:使用pipenv管理依赖包
|
||
```
|
||
注意: 如果不熟悉pipenv, 可以跳过该步骤。
|
||
```
|
||
|
||
1) 安装pipenv
|
||
```
|
||
# 建议在项目根目录下执行命令安装
|
||
pip install pipenv
|
||
```
|
||
|
||
2) 使用pipenv管理安装环境依赖包:pipenv install (必须在项目根目录下执行)
|
||
```
|
||
注意:使用pipenv install会自动安装Pipfile里面的依赖包,该依赖包仅安装在虚拟环境里,不安装在测试机。
|
||
```
|
||
|
||
方法二:直接将依赖包安装在本机
|
||
```
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
扩展: 使用 pipreqs 生成 requirements.txt
|
||
```
|
||
# 安装
|
||
pip install pipreqs
|
||
# 在当前目录生成
|
||
pipreqs . --encoding=utf8 --force
|
||
注意 --encoding=utf8 为使用utf8编码,不然可能会报UnicodeDecodeError: 'gbk' codec can't decode byte 0xae in position 406: illegal multibyte sequence 的错误。
|
||
|
||
--force 强制执行,当 生成目录下的requirements.txt存在时覆盖。
|
||
```
|
||
|
||
如上环境都已经搭建好了,包括框架依赖包也都安装好了。
|
||
|
||
<br/>
|
||
|
||
注意:
|
||
- 很多同学不太熟悉pipenv,会存在问题:比如我按照上述操作安装了依赖包,怎么运行报错呢?一定要记住,使用pipenv安装依赖包,依赖包只安装在虚拟环境,不安装在你的测试机器。所以你安装完成后,直接运行肯定会报错。我们需要进入我们创建的虚拟环境,再运行测试代码。具体步骤参考:章节"运行自动化测试"。
|
||
- 如果存在Python版本与我的不一致的问题,请移步最后的章节"初始化项目可能遇到的问题", 查找解决办法。
|
||
- 另外,我们如果是使用pycharm直接右键run的情况,我们需要pycharm解释器选择我们创建的虚拟环境,才不会报少包的错误。
|
||
|
||
|
||
## 五、如何创建用例
|
||
|
||
### 1. 修改配置文件 `config.settings.py`
|
||
1)确认用例是通过YAML还是Excel编写,由CASE_FILE_TYPE控制
|
||
2)确认测试完成后是否发送测试结果,由SEND_RESULT_TYPE控制,并填充对应邮件/钉钉/企业微信配置信息
|
||
3)确认测试是否需要进行数据库断言,如有需求,填充数据库配置信息
|
||
4)指定日志收集级别,由LOG_LEVEL控制
|
||
|
||
### 2. 修改全局变量,增加测试数据 `config.settings.py`
|
||
1)确认RunConfig的各项参数,可以调整失败重跑次数`rerun`, 失败重跑间隔时间`reruns_delay`,当达到最大失败数,停止执行`max_fail`
|
||
2)确认测试完成后是否发送测试结果,由SEND_RESULT_TYPE控制,并填充对应邮件/钉钉/企业微信配置信息
|
||
3)指定日志收集级别,由LOG_LEVEL控制
|
||
4) 配置测试相关数据:
|
||
ENV_VARS["common"]是一些公共参数,如报告标题,报告名称,测试者,测试部门。后续会显示在测试报告上。如果还有其他,可自行添加
|
||
ENV_VARS["test"]是保存test环境的一些测试数据。ENV_VARS["live"]是保存live环境的一些测试数据。如果还有其他环境可以继续增加,例如增加ENV_VARS["dev"] = {"host": "", ......}
|
||
|
||
### 3. 删除框架中的示例用例数据
|
||
1)删除 `interface`目录下所有的YAML和EXCEL文件(每一个文件都保存的接口测试用例)
|
||
2)删除 `test_case/test_manual_case`目录下所有手动编写的用例,后续有需要可以在该目录下手动编写用例。
|
||
|
||
注意:conftest.py文件中非业务相关的代码可以保留。
|
||
|
||
### 4. 编写测试用例(两种方式任选其一或者都选)
|
||
#### 1)自动生成测试用例 `data` `test_case.test_auto_case`
|
||
- 在目录`interface`下新建一个YAML/Excel文件。按照如下字段要求进行测试用例数据添加
|
||
- 注意:如果需要自动创建测试用例文件,YAML/Excel文件的文件名需要以"test"开头。
|
||
|
||
|
||
#### 2)手动编写测试用例 `interface` `test_case.test_manual_case`
|
||
- 原则上,如果是手动编写测试用例(python代码), 测试用例数据文件不要以"test"开头。 如果以“test”开头,可能导致用例运行多次。
|
||
1)在目录`interface`下新建一个YAML/Excel文件,按照要求编写测试用例数据
|
||
2)在test_case.test_manual_case下新建一个以"test"开头的测试方法,进行测试用例方法编写。
|
||
|
||
### 5. 用例中相关字段的介绍
|
||
|
||
```yaml
|
||
case_common: # 公共参数
|
||
allure_epic: 用作于@allure.epic()装饰器中的内容。
|
||
allure_feature: 用作于@allure.feature()装饰器中的内容。
|
||
allure_story: 用作于@allure.story()装饰器中的内容。
|
||
case_markers: 给测试方法添加标记,支持自定义标记,skip, usefixtures。 格式是列表嵌套字符串或者字典。例如: # ['glcc', {'skip': '跳过执行该用例'}]
|
||
|
||
common_dependence: # 放置公共依赖, 作用范围是class
|
||
setup:
|
||
interface:
|
||
database:
|
||
env_vars:
|
||
teardown:
|
||
interface:
|
||
database:
|
||
env_vars:
|
||
case_info: # 具体的用例数据,是以列表的形式进行管理
|
||
-
|
||
id: 用例id,注意需要全局唯一,方便后续用于用例接口依赖
|
||
title: 用例标题
|
||
severity: 用例优先级,支持如下几种:NORMAL, BLOCKER,CRITICAL,MINOR,TRIVIAL; 为空和错误都认为是NORMAL
|
||
run: 是否执行用例,为空或者True都会执行,为False则不执行。
|
||
url: 请求路径(可填写全路径 或者 资源路径)。通常我们填写资源路径。在用例执行前,会针对路径进行处理。具体可见case_utils.request_control.py.RequestPreDataHandle.url_handle。注:请求路径=基准路径(host/base_url)+资源路径(url)。
|
||
method: 请求方式,例如:GET, POST, DELETE, PUT, PATCH等
|
||
headers: 请求头,注意如果在headers里面防止cookies,其值类型需要是字符串
|
||
cookies: 请求cookies,格式是:DICT, CookieJar对象
|
||
request_type: 请求数据类型:params, json, file, data
|
||
payload: 请求参数
|
||
files: 需要上传的文件的相对路径,会自动拼接files目录。 os.path.join(files, "这里传递的files参数值")
|
||
wait_seconds: 选填,接口请求后的等待时间,单位是秒。传递错误,会被认为是空
|
||
assert_response: 响应断言
|
||
assert_sql: 数据库断言
|
||
extract: 后置提取参数
|
||
case_dependence: # 用例依赖, 作用范围是function
|
||
setup:
|
||
interface:
|
||
database:
|
||
env_vars:
|
||
teardown:
|
||
interface:
|
||
database:
|
||
env_vars:
|
||
```
|
||
|
||
### 6. 参数提取说明
|
||
目前支持从响应数据(response)、数据库(database)、用例数据(case)中提取数据。
|
||
目前支持3种方式的参数提取:type_jsonpath, type_re, type_response
|
||
|
||
注意:
|
||
- 提取来源关键字:case, response, database必须保持完全一致;
|
||
- 提取方式关键字:type_jsonpath, type_re, type_response必须保持完全一致;
|
||
|
||
#### 1)从响应数据中提取参数
|
||
目前从响应数据中提取参数,支持提取方式:type_jsonpath, type_re, type_response。
|
||
|
||
参考写法如下:
|
||
```
|
||
extract:
|
||
response:
|
||
type_jsonpath:
|
||
res_j_nickname: $.username
|
||
type_re:
|
||
res_re_nickname: \"username":"(.*?)"
|
||
type_response:
|
||
cookies1: response.cookies
|
||
```
|
||
|
||
其中`res_j_nickname`表示提取的变量名,后续会保存在全局变量`GLOBAL_VARS`中, 可以直接在其他接口中使用:`${res_j_nickname}`
|
||
其中`$.username`表示提取表达式,根据提取方式来写不同的表达式,表达式要写正确,否则提取不到值。
|
||
注意:
|
||
- jsonpath提取方式`type_jsonpath`,如果提取到的值是长度为1的列表,会自动获取第一个元素,其值类型由list变更为str。例如通过`name: $.data` 提取到的值是:`["flora"]`, 最后name的值会是`"flora"`。
|
||
- 正则表达式提取方式`type_re`,如果提取到的值是长度为1的列表,会自动获取第一个元素,其值类型由list变更为str。例如通过`name: "username":"(.*?)"` 提取到的值是:`["flora"]`, 最后name的值会是`"flora"`。
|
||
- 响应对应提取方式`type_response`, 则可以获取Reponse对应自带方法的一些值,例如`response.status_code`, `response.cookies`, `response.text`, `response.headers`, `response.is_redirect`等。;
|
||
|
||
|
||
|
||
注意:之前老版本是没有指定提取来源的,本次更新兼容了老版本的写法:
|
||
```
|
||
extract:
|
||
type_jsonpath:
|
||
res_j_nickname: $.username
|
||
type_re:
|
||
res_re_nickname: \"username":"(.*?)"
|
||
type_response:
|
||
cookies1: response.cookies
|
||
```
|
||
|
||
|
||
#### 2)从用例数据中提取参数
|
||
目前从响应数据中提取参数,支持提取方式:type_jsonpath, type_re。
|
||
|
||
参考写法如下:
|
||
```
|
||
case:
|
||
type_jsonpath:
|
||
case_login: $.payload.login
|
||
type_re:
|
||
case_url_key: "'url': 'https?://[^/]+/api/(.*?)/login.json'"
|
||
```
|
||
注意:假如需要提取url中的参数,由于url我们是处理过的。比如用例数据中的url是`/api/login.json`,但是实际执行过程中的url是带有域名的 `https://www.gitlink.org.cn/api/login.json` ,因此提取表达式需要将目标值对准是有域名的url。
|
||
|
||
#### 3)从数据库中提取参数
|
||
目前从响应数据中提取参数,支持提取方式:type_jsonpath, type_re。
|
||
|
||
注意:
|
||
- 查询数据库的方法我用的是查询所有,如果有多条符合条件的数据,则返回所有数据。查询结果是list格式;
|
||
- 如果不需要查询数据库,`setting.py`中的`ENV_VARS`中对应环境的`db_info`字段为空。代码中判断了`db_info`字段不为空,才进行数据库参数提取。
|
||
|
||
参考写法如下:
|
||
```
|
||
database:
|
||
# 数据库查询用的是查询所有符合条件的数据,查询结果是一个列表
|
||
sql: select * from users limit 2;
|
||
type_re:
|
||
sql_re_nickname: "'login': '(.*?)'"
|
||
type_jsonpath:
|
||
sql_j_login: $..login
|
||
```
|
||
|
||
### 7. 断言方式
|
||
以下是支持的几种断言方式:
|
||
| 断言方式 | 说明 |
|
||
| ------------ | ------------ |
|
||
| == | 相等,判断预期结果是否等于实际结果 |
|
||
| lt | 小于, 判断预期结果是否小于实际结果 |
|
||
| le | 小于等于, 判断预期结果是否小于等于实际结果 |
|
||
| gt | 大于, 判断预期结果是否大于实际结果 |
|
||
| ge | 大于等于,判断预期结果是否大于等于实际结果 |
|
||
| not_eq | 不相等,判断预期结果是否不等于实际结果 |
|
||
| str_eq | 字符串相等,判断预期结果是否等于实际结果 |
|
||
| len_eq | 长度等于,判断预期结果是否等于实际结果的长度 |
|
||
| len_gt | 长度大于,判断预期结果是否大于实际结果的长度 |
|
||
| len_ge | 长度大于等于,判断预期结果是否大于等于实际结果的长度 |
|
||
| len_lt | 长度小于,判断预期结果是否小于实际结果的长度 |
|
||
| len_le | 长度小于等于,判断预期结果是否小于等于实际结果的长度 |
|
||
| contains | 包含,判断预期结果内容被实际结果包含, 预期结果 in 实际结果 |
|
||
| contained_by | 被包含,判断预期结果包含实际结果, 实际结果 in 预期结果 |
|
||
| startswith | 以什么开头,判断实际结果是否是以预期结果开头的 |
|
||
| endswith | 以什么结尾,判断实际结果是否是以预期结果结尾的 |
|
||
|
||
### 8. 响应断言说明
|
||
#### 断言状态码
|
||
如果想要断言接口响应码,直接这样写即可:
|
||
参考示例:
|
||
```
|
||
assert_response:
|
||
status_code: 200
|
||
```
|
||
|
||
#### 响应数据断言
|
||
|
||
响应断言的参数说明:
|
||
```
|
||
断言标识(自定义,不为空即可,没有实际的意义):
|
||
message: 断言信息,非必填,可为空
|
||
expect_value: 预期结果
|
||
assert_type: 断言类型,支持如下:==, lt, le, gt, ge, not_eq, str_eq, len_eq, len_gt, len_ge, len_lt, len_le, contains, contained_by, startswith, endswith
|
||
type_jsonpath: 通过jsonpath表达式从response.json()提取实际结果,与type_re任选其一
|
||
type_re: 通过正则表达式从response.text提取实际结果,与type_jsonpath任选其一;如果不填,则默认获取response.text作为实际结果
|
||
```
|
||
|
||
注意:在进行断言的时候,左侧是预期结果,右侧是实际结果。比如我断言类型是`lt`, 那么就是预期结果<实际结果
|
||
|
||
参考示例:
|
||
```
|
||
assert_response:
|
||
user_id:
|
||
message: 断言接口返回的user_id
|
||
expect_value: ${user_id}
|
||
assert_type: ==
|
||
type_jsonpath: $.user_id
|
||
```
|
||
|
||
```
|
||
assert_response:
|
||
user_id:
|
||
expect_value: ${user_id}
|
||
assert_type: ==
|
||
type_jsonpath: $.user_id
|
||
```
|
||
|
||
### 9. 数据库断言说明
|
||
数据库断言的参数说明:
|
||
```
|
||
断言标识(自定义,不为空即可,没有实际的意义):
|
||
message: 断言信息,非必填,可为空
|
||
sql: 数据库查询语句,必填
|
||
expect_value: 预期结果
|
||
assert_type: 断言类型,支持如下:==, lt, le, gt, ge, not_eq, str_eq, len_eq, len_gt, len_ge, len_lt, len_le, contains, contained_by, startswith, endswith
|
||
type_jsonpath: 通过jsonpath表达式通从数据库查询结果提取实际结果,与type_re任选其一
|
||
type_re: 通过正则表达式从数据库查询结果提取实际结果,与type_jsonpath任选其一;如果不填,则默认SQL直接查询结果作为实际结果
|
||
```
|
||
|
||
注意:在进行断言的时候,左侧是预期结果,右侧是实际结果。比如我断言类型是`lt`, 那么就是预期结果<实际结果
|
||
|
||
参考示例:
|
||
```
|
||
assert_sql:
|
||
contains_user:
|
||
message: 断言数据库:查询tokens表,表中存在该登录用户记录;预期查询结果的长度为1
|
||
sql: select * from tokens where user_id=${user_id};
|
||
expect_value: 1
|
||
assert_type: len_eq
|
||
contains_user2:
|
||
message: 断言数据库:查询tokens表,表中存在该登录用户记录;预期 ${user_id} in 查询结果(jsonpath式匹配后的结果)
|
||
sql: select * from tokens where user_id=${user_id};
|
||
type_jsonpath: $..user_id
|
||
expect_value: ${user_id}
|
||
assert_type: ==
|
||
contains_user3:
|
||
message: 断言数据库:查询tokens表,表中存在该登录用户记录;预期 ${user_id} in 查询结果(正则表达式匹配后的结果)
|
||
sql: select * from tokens;
|
||
type_re: "'user_id': (.*?),"
|
||
expect_value: ${user_id}
|
||
assert_type: contains
|
||
```
|
||
### 10. 用例依赖说明
|
||
目前支持3种依赖方式:环境变量依赖(env_vars),接口依赖(interface),数据库查询依赖(database)。
|
||
用例依赖分为有2个范围,case_dependence作用于function,common_dependence作用于class。
|
||
用例依赖分为前置setup和后置依赖teardown。
|
||
|
||
注意:
|
||
- 依赖关键字:env_vars, interface, database必须保持完全一致;
|
||
- 提取方式关键字:type_jsonpath, type_re必须保持完全一致;
|
||
- 不同依赖方式,不同作用范围,前置和后置可以不同时存在,也可以同时存在;
|
||
|
||
#### 1)环境变量依赖(env_vars)
|
||
环境变量依赖信息, 字典格式,key为环境变量名称,value为环境变量值。value可以为常量,也可以为data_handle内支持的方法,也可以是全局变量。为空时表示没有依赖。
|
||
参考写法如下(单个用例的依赖,作用域是function):
|
||
```
|
||
case_dependence:
|
||
setup:
|
||
env_vars:
|
||
pms_project_words: ${generate_words()}
|
||
teardown:
|
||
env_vars:
|
||
user_login: flora
|
||
```
|
||
参考写法如下(用例方法的依赖,作用域是class):
|
||
```
|
||
common_dependence:
|
||
setup:
|
||
env_vars:
|
||
pms_project_words: ${generate_words()}
|
||
teardown:
|
||
env_vars:
|
||
user_login: flora
|
||
```
|
||
|
||
#### 2)接口依赖(interface)
|
||
用例依赖的接口id,支持str和list格式。接口id指的是每一个YAML/EXCEL用例中的ID。
|
||
参考写法如下(单个用例的依赖,作用域是function):
|
||
```
|
||
case_dependence:
|
||
setup:
|
||
interface: pms_get_project_user_list_01
|
||
teardown:
|
||
interface:
|
||
- pms_get_project_user_list_01
|
||
- pms_get_enterprise_user_list_01
|
||
```
|
||
参考写法如下(用例方法的依赖,作用域是class):
|
||
```
|
||
common_dependence:
|
||
setup:
|
||
interface: pms_get_project_user_list_01
|
||
teardown:
|
||
interface:
|
||
- pms_get_project_user_list_01
|
||
- pms_get_enterprise_user_list_01
|
||
```
|
||
|
||
#### 3)数据库查询依赖(database)
|
||
数据库依赖支持dict和list方式。提取方式支持两种:type_jsonpath, type_re。
|
||
注意:
|
||
- 必须要有sql关键字。并且查询数据库的方法我用的是查询所有,如果有多条符合条件的数据,则返回所有数据。查询结果是list格式;
|
||
- 如果存在数据库依赖,setting.py中的ENV_VARS中对应环境的db_info字段必须不为空,才进行数据库相关操作。
|
||
|
||
参考写法如下(单个用例的依赖,作用域是function):
|
||
```
|
||
case_dependence:
|
||
setup:
|
||
database:
|
||
sql: select * from pms_project limit 2;
|
||
type_re:
|
||
sql_re_project_assignee_id: "(?<=project_assignee_id': )[^,]+"
|
||
type_jsonpath:
|
||
sql_j_project_assignee_id: $..project_assignee_id
|
||
teardown:
|
||
database:
|
||
-
|
||
sql: select * from pms_project limit 2;
|
||
type_re:
|
||
sql_re_project_assignee_id: "(?<=project_assignee_id': )[^,]+"
|
||
type_jsonpath:
|
||
sql_j_project_assignee_id: $..project_assignee_id
|
||
```
|
||
参考写法如下(用例方法的依赖,作用域是class):
|
||
```
|
||
common_dependence:
|
||
setup:
|
||
database:
|
||
sql: select * from pms_project limit 2;
|
||
type_re:
|
||
sql_re_project_assignee_id: "(?<=project_assignee_id': )[^,]+"
|
||
type_jsonpath:
|
||
sql_j_project_assignee_id: $..project_assignee_id
|
||
teardown:
|
||
database:
|
||
-
|
||
sql: select * from pms_project limit 2;
|
||
type_re:
|
||
sql_re_project_assignee_id: "(?<=project_assignee_id': )[^,]+"
|
||
type_jsonpath:
|
||
sql_j_project_assignee_id: $..project_assignee_id
|
||
```
|
||
|
||
|
||
|
||
### 11. Excel用例单独说明
|
||
框架支持excel多表单自动生成测试用例,每一个表单作为一个测试用例模块。
|
||
例如:
|
||
excel表格名称是:test_demo.xlsx
|
||
excel表单1名称是:GitLink-登录模块
|
||
excel表单2名称是:示例模块
|
||
|
||
|
||
生成规则:
|
||
- 如果excel表单中存在"-",我们将取"-"后面的部分的首字母拼接excel文件名称作为测试用例模块/测试用例类/测试用例方法名称
|
||
- 如果excel表单中不存在"-",我们将直接获取表单名称首字母拼接excel文件名称作为测试用例模块/测试用例类/测试用例方法名称
|
||
- 测试用例模块/测试用例类/测试用例方法名称同时也将遵循python语法规则进行适当调整
|
||
|
||
<br/>
|
||
|
||
基于上述规则:
|
||
- excel第一个表单生成的测试用例
|
||
测试用例模块:test_demo_dlmk.py
|
||
测试用例类:TestDemoDlmkAuto
|
||
测试用例方法:test_demo_dlmk_auto
|
||
|
||
- excel第二个表单生成的测试用例
|
||
测试用例模块:test_demo_slmk.py
|
||
测试用例类:TestDemoSlmkAuto
|
||
测试用例方法:test_demo_slmk_auto
|
||
|
||
## 六、运行自动化测试
|
||
### 方式一:使用pipenv管理虚拟环境
|
||
#### 1. 激活已存在的虚拟环境
|
||
- (如果不存在会创建一个):pipenv shell (必须在项目根目录下执行)
|
||
|
||
#### 2. 运行
|
||
```
|
||
在pycharm>terminal或者电脑命令窗口,进入项目根路径,执行如下命令(如果依赖包是安装在虚拟环境中,需要先启动虚拟环境)。
|
||
> python run.py 默认在test环境运行测试用例, 生成allure测试报告
|
||
> python run.py -m demo 在test环境仅运行打了标记demo用例,生成allure测试报告
|
||
> python run.py -env live 在live环境运行测试用例
|
||
> python run.py -env=test 在test环境运行测试用例
|
||
> python run.py -report=no 在test环境下允许测试用例,不生成allure测试报告
|
||
```
|
||
或者上述步骤可以合并为:pipenv run python run.py
|
||
|
||
### 方式二:依赖包安装在本机
|
||
```
|
||
在pycharm>terminal或者电脑命令窗口,进入项目根路径,执行如下命令(如果依赖包是安装在虚拟环境中,需要先启动虚拟环境)。
|
||
> python run.py 默认在test环境运行测试用例, 生成allure测试报告
|
||
> python run.py -m demo 在test环境仅运行打了标记demo用例,生成allure测试报告
|
||
> python run.py -env live 在live环境运行测试用例
|
||
> python run.py -env=test 在test环境运行测试用例
|
||
> python run.py -report=no 在test环境下允许测试用例,不生成allure测试报告
|
||
```
|
||
|
||
注意:
|
||
- 如果pycharm.interpreter拥有了框架所需的所有依赖包,可以通过pycharm直接在`run.py`中右键运行
|
||
|
||
## 七、查看测试报告
|
||
### Allure测试报告
|
||
1. Allure生成的测试报告,支持通过pycharm,点击`outputs/report/allure_html/index.html`,文件右上角选择浏览器打开查看测试报告
|
||
2. 如果不通过pycharm打开,直接通过文件夹打开,windows系统环境下,可以点击`outputs/report/allure_html/双击打开Allure报告.bat`打开查看测试报告
|
||
|
||
<br/>
|
||
|
||
注意:
|
||
- 通过点击`outputs/report/allure_html/双击打开Allure报告.bat`打开测试报告的方法,暂时不支持mac系统
|
||
- 如果通过点击`outputs/report/allure_html/双击打开Allure报告.bat`打开测试报告,命令窗口显示乱码,或者打不开,可以把`.bat`的文件名称修改为英文的名称,里面的所有中文注释全部移除,再次尝试
|
||
|
||
|
||
## 八 、详细功能说明
|
||
- [如何实现动态数据、随机数据的热加载?](https://www.gitlink.org.cn/zone/tester/newdetail/236)
|
||
我们有些特殊的场景,可能会涉及到一些定制化的数据,每次执行数据,需要按照指定规则随机生成,实时加载数据,那么这部分应该如何处理呢?
|
||
|
||
- [如何处理同一环境存在多域名的情况?](https://www.gitlink.org.cn/zone/tester/newdetail/234)
|
||
很多公司,通常一套环境是由多个微服务组成。每一个微服务具备不同的域名。那么针对这种同一环境存在多域名的情况,我们应该如何处理呢?
|
||
|
||
- [如何处理同一套框架测试多套环境的情况?](https://www.gitlink.org.cn/zone/tester/newdetail/233)
|
||
假如我想要我的自动化代码分别在不同环境执行,如何处理呢?
|
||
|
||
- [如何处理用例中需要依赖登录的token/cookies的情况?](https://www.gitlink.org.cn/zone/tester/newdetail/235)
|
||
我们进行测试的时候,很多接口都是需要先登录之后再进行操作。但是我们不可能每测试一次接口,都登录一次吧,这样有点冗余了。那么,针对这种情况如何处理呢?
|
||
|
||
- [如何测试上传文件接口?](https://www.gitlink.org.cn/zone/tester/newdetail/238)
|
||
我们通过MultipartEncoder的方式进行文件上传。
|
||
|
||
- [如何通过用例数据动态配置pytest.mark](https://www.gitlink.org.cn/zone/tester/newdetail/257)
|
||
在测试过程中,我们经常需要对测试用例进行分类,运行时仅执行这一类用例。为了实现这一功能,我在测试用例中引入了添加pytest的自定义标记的功能,同时扩展支持了pytest.mark.skip以及pytest,mark.usefixtues。
|
||
注意:目前这一功能,仅支持通过YAML格式编写用例。EXCEL用例暂时不支持。
|
||
|
||
- [如何设置测试用例优先级](https://www.gitlink.org.cn/zone/tester/newdetail/260)
|
||
测试用例会分优先级, 我们可以利用allure的特性设置用例优先级,以及运行指定优先级的用例。
|
||
|
||
- [如何提取响应数据作为全局变量并使用?](https://www.gitlink.org.cn/zone/tester/newdetail/237)
|
||
在测试过程中,通常下一个接口需要用到上一个接口的响应数据,这个时候就涉及到参数的提取。
|
||
|
||
- [如何进行响应数据断言以及数据库断言?](https://www.gitlink.org.cn/zone/tester/newdetail/239)
|
||
目前支持的断言方式:==, lt, le, gt, ge, not_eq, str_eq, len_eq, len_gt, len_ge, len_lt, len_le, contains, contained_by, startswith, endswith
|
||
|
||
- [如何配置邮箱通知?](https://www.gitlink.org.cn/zone/tester/newdetail/242)
|
||
我们通过第三方模块yagmail发送邮件。
|
||
|
||
- [如何配置钉钉通知?](https://www.gitlink.org.cn/zone/tester/newdetail/243)
|
||
我们通过封装钉钉机器人发送钉钉通知。
|
||
|
||
- [如何配置企业微信通知?](https://www.gitlink.org.cn/zone/tester/newdetail/241)
|
||
我们通过封装企业微信机器人发送通知。
|
||
|
||
- [python虚拟管理工具--pipenv使用教程](https://www.gitlink.org.cn/zone/tester/newdetail/505)
|
||
在使用Python语言的时候我们使用pip来安装第三方包,但是由于pip的特性,系统中只能安装每个包的一个版本。但是在实际项目开发中,不同项目可能需要第三方包的不同版本,Python的解决方案就是虚拟环境。
|
||
顾名思义,虚拟环境就是虚拟出来的一个隔离的Python环境,每个项目都可以有自己的虚拟环境,用pip安装各自的第三方包,不同项目之间也不会存在冲突。
|
||
创建虚拟环境需要一些工具, 我们使用pipenv来创建虚拟环境和管理依赖包。
|
||
|
||
- [如何调试单个用例?](https://www.gitlink.org.cn/zone/tester/newdetail/512)
|
||
有些小伙伴在测试的时候,想要单独调试用例,但是不清楚如何调试。本文将详细讲解~
|
||
|
||
- [如何重复执行用例?](https://www.gitlink.org.cn/zone/tester/newdetail/514)
|
||
平常在做功能测试的时候,经常会遇到某个模块不稳定,偶然会出现一些bug,对于这种问题我们会针对此用例反复执行多次,最终复现出问题来。
|
||
自动化运行用例时候,也会出现偶然的bug,可以针对单个用例重复执行多次。
|
||
|
||
- [pytest-xdist(分布式执行)](https://www.gitlink.org.cn/zone/tester/newdetail/785)
|
||
当测试用例非常多的时候,一条条按顺序执行测试用例,是很浪费测试时间的。这时候就可以用到 pytest-xdist,让自动化测试用例可以分布式执行,从而大大节省测试时间。
|
||
|
||
## 九、初始化项目可能遇到的问题
|
||
- [测试机安装python版本与本框架要求不一致,怎么办?](https://www.gitlink.org.cn/zone/tester/newdetail/245)
|
||
- [无法安装依赖包或者安装很慢,怎么办?](https://www.gitlink.org.cn/zone/tester/newdetail/244)
|
||
|
||
|
||
## ## 🐳 Docker构建运行
|
||
前提条件:
|
||
- 宿主机已经安装docker
|
||
- 仓库根目录下已编写好`dockerfile`
|
||
|
||
### 1.构建镜像
|
||
**语法**:`docker build -f Dockerfile的路径 -t 镜像的名称及标签 镜像构建的目录`
|
||
- `-f`:指定 Dockerfile 文件路径(可使用绝对/相对路径)
|
||
- `-t`:指定镜像名称及标签格式 `[name]:[tag]`
|
||
- `.`:表示当前构建上下文目录
|
||
- `--no-cache` 表示禁用缓存
|
||
|
||
**示例**:
|
||
```bash
|
||
docker build -f dockerfile --no-cache -t apitest:2.0 .
|
||
```
|
||
|
||
### 2. 运行镜像
|
||
**语法**:`docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG…]`
|
||
- `-d/–detach`:后台运行容器
|
||
- `p/–publish`:端口映射格式 [主机IP:]主机端口:容器端口[/协议]
|
||
- `–name`:指定容器名称(未指定时会自动生成随机名称)
|
||
- `-e/–env`:设置环境变量
|
||
- `-v/–volume`:挂载数据卷(将宿主机上的一个目录(文件夹)/文件挂载到容器内的指定目录/文件,使得容器内的该目录/文件与宿主机保持同步。)
|
||
- `–restart`:设置重启策略(如 –restart=always)
|
||
|
||
**示例**:
|
||
```bash
|
||
docker run --rm --name apitest -e NGINX="http://xxx" -v -v /data/nginx/html/apiautotest/:/apiautotest/ -v /data/chytest/env/test.yaml:/apiautotest/env/test.yaml apitest:2.0
|
||
|
||
docker run \
|
||
-v /data/nginx/html/apiautotest/:/apiautotest/ \
|
||
-v /data/chytest/env/test.yaml:/apiautotest/env/test.yaml \
|
||
-e NGINX="http://xxx" \
|
||
--name apitest \
|
||
apitest:2.0
|
||
```
|
||
|
||
- 挂载目录
|
||
将宿主机的 `/data/nginx/html/apiautotest/` 目录挂载到容器内的 `/apiautotest/` 目录:
|
||
(运行的时候,会运行宿主机目录`/apiautotest/`的文件,运行完成后,将宿主机目录`/data/nginx/html/apiautotest/`拷贝到容器内的目录`/apiautotest/`)
|
||
`-v /data/nginx/html/apiautotest/output/:/apiautotest/output/`
|
||
|
||
- 挂载单个文件
|
||
将宿主机的 `/data/chytest/env/test.yaml` 文件挂载到容器内的 `/apiautotest/env/test.yaml` 文件:
|
||
(实际运行的时候,会读取将宿主机的 `/data/chytest/env/test.yaml`的内容作为测试数据)
|
||
`-v /data/chytest/env/test.yaml:/apiautotest/env/test.yaml`
|
||
|
||
### 3. 流水线参考
|
||
```yaml
|
||
name: "接口测试-生成报告"
|
||
on:
|
||
push:
|
||
branches:
|
||
- '*'
|
||
paths-ignore:
|
||
- '.gitea/workflows/**'
|
||
- '.github/workflows/**'
|
||
jobs:
|
||
job-487fcffc:
|
||
name: "测试[job-487fcffc]"
|
||
# 运行环境,这里就是上面定义的多个 os
|
||
runs-on: 'ubuntu-latest'
|
||
steps:
|
||
- name: "克隆代码[ssh-bbc2533]"
|
||
uses: http://xxx/actions/ssh-action@v1.0.3
|
||
with:
|
||
host: 'xxx'
|
||
port: '22'
|
||
username: 'root'
|
||
password: 'xxx'
|
||
script: 'cd /data/nginx/html/ && git clone --recurse-submodules https://gitlink.org.cn/kytest/apiautotest.git>/dev/null || echo "代码已存在无需重新克隆,仅需拉取最新代码" && cd /data/nginx/html/apiautotest && git pull --force origin master:master && git log -1 '
|
||
- name: "ssh登录服务器[ssh-1bd148b]"
|
||
uses: http://xxx/actions/ssh-action@v1.0.3
|
||
with:
|
||
host: 'xxx'
|
||
port: '22'
|
||
username: 'root'
|
||
password: 'xxx'
|
||
script: 'cd /data/nginx/html/apiautotest && docker build -f dockerfile --no-cache -t apitest:2.0 .>/dev/null || echo "镜像已存在无需构建" && docker images | grep apitest'
|
||
- name: "执行测试[ssh-7cf8368e]"
|
||
uses: http://xxx/actions/ssh-action@v1.0.3
|
||
with:
|
||
host: 'xxx'
|
||
port: '22'
|
||
username: 'root'
|
||
password: 'xxx'
|
||
script: 'docker run --rm --name apitest -e NGINX="http://xxx:8001" -v /data/nginx/html/apiautotest/:/apiautotest/ apitest:2.0'
|
||
- name: "获取测试报告信息[log_match_action-7515d3d]"
|
||
uses: http://xxx/xxq250/log_match_action@master
|
||
with:
|
||
match-step: '3'
|
||
match-key: 'out: 测试报告地址:'
|
||
match-job-name: '自动化测试报告'
|
||
upload-api-domain: ''
|
||
check-contains-link: ''
|
||
show-type: 'html'
|
||
```
|
||
|
||
## 赞赏
|
||
如果这个库有帮助到你并且你很想支持库的后续开发和维护,那么你可以扫描下方二维码随意打赏我,我将不胜感激~
|
||
<img src="https://www.gitlink.org.cn/api/attachments/437395" style="width: 150px; height: auto;" /> |