Files
apiautotest/README.md
T

455 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 前言
公司突然要求你做自动化,但是没有代码基础不知道怎么做?或者有自动化基础,但是不知道如何系统性的做自动化, 放在yaml文件中维护,不知道如何处理多业务依赖的逻辑?
那么本自动化框架,将为你解决这些问题。
- 框架主要使用 python 语言编写,结合 pytest 进行二次开发,用户仅需要在 yaml 文件中编写测试用例, 编写成功之后,会自动生成测试用例代码。
- 如果是具备代码基础的,也可以直接通过 py 文件编写测试用例。
- 使用 Allure 生成报告,并针对测试报告样式进行了调整,使得报告更加美观;
- 测试完成后,支持发送 企业微信通知/ 钉钉通知/ 邮箱通知,灵活配置。
## 一、框架介绍
本框架主要是基于 Python + Pytest + Allure + Loguru + 邮件通知/企业微信通知/钉钉通知 实现的接口自动化框架。
* git地址: [https://www.gitlink.org.cn/floraachy/apiautotest](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)
* 入群二维码:[https://www.gitlink.org.cn/floraachy/apiautotest/issues/1](https://www.gitlink.org.cn/floraachy/apiautotest/issues/1)
如果对您有帮助,请点亮 小星星 以表支持,谢谢!
对于框架有任何问题,请先仔细阅读本文~ 如果还有不了解的,欢迎联系我!
## 二、实现功能
* 通过session会话方式,解决了登录之后cookie关联处理`
* 动态多断言: 如接口需要同时校验响应数据和sql校验,支持多场景断言
* 支持单独调试用例,支持用例的重复执行
* 框架天然支持接口动态传参、关联灵活处理
* 支持测试数据分析,测试数据不符合规范有预警机制
* 支持通过用例数据动态配置pytest.mark 包括自定义标记,pytest.mark.skip以及pytest.mark.usefixtures
* 支持利用allure设置用例优先级,运行指定优先级的用例
* 执行环境一键切换,解决多环境相互影响问题
* 自动生成用例代码: 测试人员在yaml/excel文件中填写好测试用例, 程序可以直接生成用例代码,纯小白也能使用
* 支持参数多类型提取:支持通过jsonpath从response.json提取数据;支持通过正则表达式从response.text提取数据;支持直接提取response本身的数据,例如response.cookies
* 使用Allure生成测试报告,并对测试报告进行了定制化修改,使得测试报告更加美观
* 日志模块: 采用loguru管理日志,可以输出更为优雅,简洁的日志
* 钉钉、企业微信通知: 支持多种通知场景,执行成功之后,可选择发送钉钉、或者企业微信、邮箱通知
* 使用pipenv管理虚拟环境和依赖文件,提供了一系列命令和选项来帮助你实现各种依赖和环境管理相关的操作
* 支持将swagger.json接口文档转为YAML用例
* 支持接口相应后添加等待时间,方便接口调用后,进行一系列数据初始化操作,待操作成功后,执行后续接口
## 三、依赖库
```
allure-pytest = "==2.9.45"
click = "==8.1.7"
faker = "==21.0.0"
loguru = "==0.7.2"
openpyxl = "==3.1.2"
pydantic = "==2.5.2"
pymysql = "==1.1.0"
pytest-rerunfailures = "==12.0"
pyyaml = "==6.0.1"
requests-toolbelt = "==1.0.0"
"ruamel.yaml" = "==0.18.5"
sshtunnel = "==0.4.0"
xpinyin = "==0.7.6"
yagmail = "==0.15.293"
pytest-repeat = "==0.9.3"
jsonpath = "*"
```
## 四、安装教程
1. 通过Git工具clone代码到本地 或者 直接下载压缩包ZIP
```
https://gitlink.org.cn/floraachy/apiautotest.git
```
2. 本地电脑搭建好 python环境,我使用的python版本是3.9。包括allure测试报告所需的java环境(安装jdk)。
3. 安装环境依赖包
1) 方法一:使用pipenv管理所有依赖
```
# 安装pipenv, 这个需要全局安装。建议在项目根目录下执行命令安装
pip install pipenv
# 使用pipenv管理安装环境依赖包(必须在项目根目录下执行)。
pipenv install
# 注意:使用pipenv install会自动安装Pipfile里面的依赖包,该依赖包仅安装在虚拟环境里,不安装在测试机(本机)。
```
2方法二:使用requirements.txt一键安装所有依赖
```
pip install -r 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) ENV_VARS["common"]是一些公共参数,如报告标题,报告名称,测试者,测试部门。后续会显示在测试报告上。如果还有其他,可自行添加
2ENV_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: # 放置公共依赖
setup:
interface:
sql:
env_vars:
teardown:
interface:
sql:
env_vars:
case_info: # 具体的用例数据,是以列表的形式进行管理
-
id: 用例id,注意需要全局唯一,方便后续用于用例接口依赖
title: 用例标题
severity: 用例优先级,支持如下几种:NORMAL BLOCKERCRITICALMINORTRIVIAL 为空和错误都认为是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: 用例依赖
```
### 6. 参数提取说明
目前支持3种方式的参数提取:type_jsonpath, type_re, type_response
#### type_jsonpath
如果采用jsonpath方式从响应数据提取参数,`extract`的key是`type_jsonpath`; `extract[type_jsonpath]`的key是变量名,value是提取表达式;
参考示例:
```
extract:
type_jsonpath:
nickname: $.username
login: $.login
user_id: $.user_id
```
注意:如果提取到的值是长度为1的列表,会自动获取第一个元素,其值类型由list变更为str。例如通过`name: $.data` 提取到的值是:`["flora"]`, 最后name的值会是`"flora"`
#### type_re
如果采用正则表达式方式从响应数据提取参数,`extract`的key是`type_re`; `extract[type_re]`的key是变量名,value是提取表达式;
参考示例:
```
# 注意:\是用来转译的,保证yaml格式正确.也可以用引号包裹起来
extract:
type_re:
nickname: \"username":"(.*?)"
login: \"login":"(.*?)"
user_id: '"user_id":(.*?),'
```
注意:如果提取到的值是长度为1的列表,会自动获取第一个元素,其值类型由list变更为str。例如通过`name: "username":"(.*?)"` 提取到的值是:`["flora"]`, 最后name的值会是`"flora"`
#### type_response
如果是直接从响应数据提取参数,`extract`的key是`type_response`; `extract[type_response]`的key是变量名,value是提取表达式;
基本上response所有方法都支持,部分参考:`response.status_code` `response.cookies`, `response.text`, `response.headers`, `response.is_redirect`
参考示例:
```
extract:
type_response:
cookies: response.cookies
```
### 6. 断言方式
以下是支持的几种断言方式:
| 断言方式 | 说明 |
| ------------ | ------------ |
| == | 相等,判断预期结果是否等于实际结果 |
| 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 | 以什么结尾,判断实际结果是否是以预期结果结尾的 |
### 7. 响应断言说明
#### 断言状态码
如果想要断言接口响应码,直接这样写即可:
参考示例:
```
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
```
### 8. 数据库断言说明
数据库断言的参数说明:
```
断言标识(自定义,不为空即可,没有实际的意义):
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` 那么就是预期结果<实际结果
参考示例:
```
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
```
### 9. 用例依赖说明
目前用例依赖仅支持接口依赖和环境变量依赖。数据库依赖后续会补充。
依赖的配置说明:
```
case_dependence: 用例依赖,为空时表示没有依赖
setup: 前置依赖信息,为空时表示没有依赖
interface: 用例依赖的接口id,支持str和list格式。接口id指的是每一个YAML/EXCEL用例中的ID
sql: 数据库查询语句,后续支持后将补充
env_vars: 环境变量依赖信息, 字典格式,key为环境变量名称,value为环境变量值。value可以为常量,也可以为data_handle内支持的方法,也可以是全局变量。为空时表示没有依赖
teardown: 后置依赖信息,为空时表示没有依赖
interface: 用例依赖的接口id,支持str和list格式。接口id指的是每一个YAML/EXCEL用例中的ID
sql: 数据库查询语句,后续支持后将补充
env_vars: 环境变量依赖信息, 字典格式,key为环境变量名称,value为环境变量值。value可以为常量,也可以为data_handle内支持的方法,也可以是全局变量。为空时表示没有依赖
```
参考示例:
```
case_dependence:
setup:
interface: gitlink_login_oauth_token_01
env_vars:
repo_owner: ${env_login}
teardown:
interface:
- gitlink_projects_delete_project_01
sql:
env_vars:
env_page_content: ${generate_paragraph}
```
### 10. 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
## 六、运行自动化测试
### 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测试报告
```
注意:
- 如果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,可以针对单个用例重复执行多次。
## 九、初始化项目可能遇到的问题
- [测试机安装python版本与本框架要求不一致,怎么办?](https://www.gitlink.org.cn/zone/tester/newdetail/245)
- [无法安装依赖包或者安装很慢,怎么办?](https://www.gitlink.org.cn/zone/tester/newdetail/244)
## 赞赏
如果这个库有帮助到你并且你很想支持库的后续开发和维护,那么你可以扫描下方二维码随意打赏我,我将不胜感激~<br/>
![打赏](https://www.gitlink.org.cn/api/attachments/437395)