# api-autotest **Repository Path**: onecoco/api-autotest ## Basic Information - **Project Name**: api-autotest - **Description**: 基于 pytest的自动化测试框架 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-06-07 - **Last Updated**: 2025-06-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # PyTest ## 一、项目目录结构介绍 ```python ├── config // 待测试系统的相关配置 │ ├── app //系统 │ │ ├── config.yaml // 配置系统的数据库信息,redis信息等,区分环境 │ │ └── context.yaml // 配置系统域名、账号、一些固定数据,区分环境 │ └── setting.py // 本项目的配置文件 ├── test_case // 测试用例 │ └── app │ └── test_demo.py ├── test_data // 测试数据 │ └── app │ │ └── test_demo.yaml │ └── file // 存放资源文件,上传文件 ├── .env // 本项目的配置文件 ├── main.py // 执行入口 ├── pytest.ini // pytest配置 ├── README.md // 使用文档 └── requirements.txt // 项目依赖包 ``` ## 二、安装项目依赖 ```python # 进入项目跟目录,执行如下命令 pip install -r .\requirements.txt ``` ## 三、创建应用 本项目支持管理多个系统的测试用例,每个系统用例是相互隔离,运行时需要指定系统名称(应用名称)及执行环境 ### 创建应用命令 ```python # 命令格式 python create_app.py [应用名称] # 例如创建名称为camp的应用,用于管理demo系统相关用例 python -m framework.startapp demo ``` 执行命令后会在指定目录下生成应用的相关配置及目录 ![image-20250607094342380](test_data/file/image-20250607094342380.png) #### config目录 在config目录下会新增一个名称为demo的文件夹,文件夹中包含两个文件`context.yaml`,`config.yaml` - `context.yaml`: 用于存放demo系统的域名、账号等一些固定数据。并且需要区分环境。 ```yaml # context.yaml dev: domain: dev.example.com accounts: admin: username: admin password: test rsa_public_key: xxxxxxxxxxxxxxx user_id: 123 ``` - `config.yaml`: 用于存放demo系统中间件的配置信息,例如Mysql、Redis的信息。并且需要区分环境。 ```yaml dev: mysql: host: null username: null password: null port: 3306 redis: host: null password: null port: 6379 db: 0 ``` #### test_case目录 在test_case目录下会新增一个名称为demo的文件夹,文件夹中会包含一个测试用例示例`test_untitled.py`。后续测试用例需要写在这个文件夹下,可以建子目录。 ![image-20250607094716021](test_data/file/image-20250607094716021.png) ```python from test_case import BaseTestCase class TestUntitled(BaseTestCase): def test_untitled(self): # 发送请求 self.request("demo", "admin", self.data) # 断言 assert self.response.status_code == 200 assert len(self.response.jsonpath("$.data.balances")) > 0 ``` #### test_data目录 在test_data目录下会新增一个名称为demo的文件夹,文件夹中会包含一个测试数据示例`test_untitled.yaml`。后续测试数据都写在这个文件夹下,可以建子目录,**子目录不需要与test_case的目录结构一致**。 ![image-20250607095009032](test_data/file/image-20250607095009032.png) ```yaml case_common: module: 功能模块名称 describe: 测试场景描述 test_untitled: title: 登录成功 # 用例标题 level: p0 # 用例等级 request: url: /login # 接口路径 method: post # 请求方式 json: # 发送数据格式 name: Jerry extract: # 提取响应内容中的变量 - id: $.data.token ``` #### conftest.py文件 在conftest文件中会新增一个名为DemoLogin的类。需要在该方法中实现登录。 ![image-20250607095327697](test_data/file/image-20250607095327697.png) ```python class DemoLogin(Login): def login(self, username, password, secret_key): client = HttpClient() # TODO 需要实现登录逻辑,将登录获取到的token添加到headers中 return client ``` ## 四、编写用例 ### 编写测试脚本 #### 测试脚本命名规范 - 文件名必须以`test_`开头 - 类名行必须以`Test`开头,遵循大驼峰命名方式 - 方法必须以`test_`开头 #### 测试脚本模版 ```python from test_case import BaseTestCase class TestFipOpenTerm(BaseTestCase): def test_create_fip_order(self): # 用demo系统中的账号admin发送请求 self.request("demo", "client", self.data) # 断言 assert self.response.status_code == 200 assert self.response.jsonpath("$.code") == 0 assert self.response.jsonpath("$.data.subscriptionAmount") > 0 self.validate_fip_order() def validate_fip_order(self): # 验证列表中有总订单 resp = self.post( app="demo", account="user", url="/prod-api/wealth/client/investment/holding/fip/open", json={"settledOrderFlag": False} ) assert resp.jsonpath("$.code") == 0 assert len(resp.jsonpath("$.data")) > 0 # 验证数据库有新插入的子订单 data = self.mysql_conn("db_camp_wealth").query( f"SELECT * FROM tbl_fip_open_order WHERE email='{self.context.demo.accounts.user.username}' order by id DESC limit 1;") assert data.get("subscription_amount") == 12000 ``` ### 编写测试数据 #### 测试数据命名规范 - yaml文件名必须与对应的测试脚本文件名一致 - yaml文件中测试数据节点名称必须与测试用例的方法名一致 ![1730859872638](test_data/file/1730859872638.png) #### 测试数据模版 ```yaml # 公共参数 case_common: module: 资产模块 # 用例所属功能模块(非必填) describe: 获取账户余额信息接口 # 对接口描述信息(非必填) test_get_fiat_balance: title: 获取法币账户余额信息 # 用例标题(必填) level: p0 # 用例等级(必填) mark: smoke # 给用例打标签(非必填) 默认会将level设置为标签 request: url: /api/client/balance/get # 接口url method: post # 请求方式 json: # json格式的数据(非必填) userId: ${client.user_id} accountType: 2 data: # 表单格式的数据(非必填) userId: ${client.user_id} accountType: 2 params: # url中的查询参数(非必填) userId: ${client.user_id} accountType: 2 extract: # 提取响应内容中的数据(非必填) - total_balance: $.data.totalBalance - usd_balance: data.balances[0].balance ``` #### 引入动态参数 ##### 使用动态参数的场景 - 接口对某些参数有唯一性校验,不能重复使用同一个值,需要使用随机值 - 对某些参数有特殊格式要求,例如某参数需要传入当前时间,格式要求为`yyyy-MM-dd HH:mm:ss` - 接口参数有依赖,必须是其他某个接口返回的字段 ##### 如何引入动态参数 使用`${}`占位符的方式引入动态参数。 - 引入context全局对象中的值,例如`${domain}`。如果目标值所在的层级比较深,可以使用句点表示式取值,例如`${client.user_id}` - 引入一个函数,并且必须是test_data>common.py中自定义的函数或Faker库中的函数。函数支持传参,仅限传位置参数。 ps: Faker库是专门用于生成各种类型随机数据的。https://blog.csdn.net/u013904878/article/details/120428011 ```yaml test_get_crypto_balance: title: 获取数字货币账户余额信息 level: p0 request: json: userId: ${client.user_id} # 引入context中的值 remark: ${text(20)} # 引入Faker库的某个函数 dataTime: ${get_current_datetime()} # 引入common.py中自定义的函数 ``` ## 五、测试报告 #### 下载安装allure 选择最新版本下载并解压到指定目录 https://github.com/allure-framework/allure2/releases ![1735787960234](test_data/file/1735787960234.png) #### 配置allure路径 将项目根目录中的.env.example文件名修改为.env allure解压完成后进入bin目录,将bin目录下allure.bat的完成路径配置到.env文件中的ALLURE_DIR字段 ![1735789023706](test_data/file/1735789023706.png) 执行完成后会在项目跟目录中生成allure_report目录,点击index.html打开报告 ![1730865221877](test_data/file/1730865221877.png) ## 六、执行用例 ```python # 进入项目跟目录,执行如下命令 python main.py --app=demo --env=dev ``` ## 七、Pycharm设置快捷命令 ### 设置创建测试数据模版快捷命令 1. 进入Settings页 (File -> Settings) ![](test_data/file/1730709350119.png) 2. 搜索框输入Live Templates (Editor -> Live Templates) ![](test_data/file/1730709528594.png) 3. 选中Python,点击+号,选择Live Templates ![](test_data/file/1730709805912.png) 4. Abbreviation输入快捷命令tmp_data(可根据个人喜好自定义命令),Template text中贴入yaml模版 ![](test_data/file/1730710585464.png) 模版 ```yaml case_common: # 公共参数 module: 功能模块名称 describe: 接口描述 url: /login method: post test_untitled: # 测试用例方法名 title: 登录成功 level: p0 request: json: name: Jerry data: name: ${name} params: name: ${text(20)} extract: # 从响应内容中提取变量 - id: $.data.token ``` 5. 点击Change,选择General .yaml file,点击OK ![](test_data/file/1730711254059.png) 6. 测试是否生效。创建yaml文件,然后输入快捷命令 回车 ![](test_data/file/1730710665403.png) ![](test_data/file/1730710427260.png) ### 设置创建测试用例模版快捷命令 置步骤与上述步骤差不多,只需要将第4,5替换如下内容 第四步:Abbreviation输入快捷命令tmp_case(可根据个人喜好自定义命令),Template text中贴入case模版 ![](test_data/file/1730711757525.png) 模版 ```python from test_case import BaseTestCase class TestUntitled(BaseTestCase): def test_untitled(self): # 断言 assert self.response.status_code == 200 assert len(self.response.jsonpath("$.data.balances")) > 0 ``` 第五步:点击Change,选择Python,点击OK ![](test_data/file/1730712010193.png) ## 八、其他 json yaml格式互转工具:https://33tool.com/json2yaml/