# AutoTestFrame **Repository Path**: chiyaun/auto-test-frame ## Basic Information - **Project Name**: AutoTestFrame - **Description**: pytest+allure+requests实现的一个零代码自动化测试框架,持续更新中 - **Primary Language**: Python - **License**: AGPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2024-08-12 - **Last Updated**: 2025-01-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: Python, playwright, Requests, pytest, Allure ## README # AutoTestFrame # 介绍 AutoTestFrame是一个基于Python的自动化测试框架,旨在帮助测试人员快速、高效地完成测试任务。 ## 软件架构 软件架构说明 pytest + requests + faker + allure + playwright ## 安装教程 `pip install -r requirements.txt` ## 使用说明 1. 该框架基于pytest,所以首先需要安装pytest。 2. 克隆项目到本地。 3. 安装依赖包。 4. 运行命令`pytest`即可运行测试用例。 5. 运行命令`allure generate ./reports -o./allure-report`生成测试报告。 6. 运行命令`allure open ./allure-report`查看测试报告。 7. 运行命令`allure serve ./allure-report`启动测试报告服务器。 或者直接运行[runner.py](runner.py)文件。 `python runner.py` ## 目录结构 ``` text AutoTestFrame ├── README.md # 说明文档 ├── AppData # 应用数据 │ ├── logs # 日志文件 │ ├── reports # 测试报告 │ ├── allure-2.30.0 # allure程序 │ └── variables # 测试用例产生的临时文件 ├── requirements.txt # 依赖包 ├── runner.py # 运行文件 ├── test_cases # 测试用例 │ ├── web # web测试用例 │ ├── api # api测试用例 │ ├── conftest.py # 获取测试结果 │ └── ... # 其他测试用例 ├── common # 公共模块 │ ├── send # 发送请求模块 │ ├── file_engine # 文件处理模块 │ ├── _models] # 配置模型等 │ ├── enums.py # 枚举模块 │ ├── logger.py # 日志模块 │ ├── tools.py # 处理工具模块 │ └── config.py # 配置文件 ├── models # 数据库模型 │ ├── api_model.py # api模型(测试用例模型库) │ ├── public.py # 公共模型 │ └── web_model.py # web模型(测试用例模型库) └── utils # 工具类 ├── api # api工具类 ├── web # web工具类 ├── main # main工具类 ├── public # 公共工具类 └── ... # 其他工具类 ``` ## 接口测试用例 ### 用例模板 ``` yaml - 模块名称: 测试登录 接口名称: 登录 用例名称: 登录成功 用例描述: 用户名正确,密码正确,登录成功 是否运行: true 请求数据: method: post url: http://127.0.0.1:5000/api/login json: userName: '15740525667' password: admin@123456 断言: - 断言方式: equal 期望值: 操作成功 实际值: 'response.json().get("msg") # 预期响应的msg值,response为requests.Response对象' 断言消息: 登录失败 提取数据: token: - json - $.data.token - 0 ``` ### 用例说明 接口测试用例的格式为 `yaml`,具体字段说明如下: - 请求数据中集成了 `faker` 库,可以随机生成用户名和密码。 - 使用方法:`${faker.name}` - `faker` 库的更多用法参考 https://faker.readthedocs.io/en/master/index.html - 请求数据集成了一些方法,可以直接使用。 - 使用方法:`${timestamp(13)}`, 获取当前时间戳 - 可以在 [data_tools_util.py](common%2Futil%2Fdata_tools_util.py)中进行拓展,实现更多的方法 - 断言中,实际响应内容可以直接使用 `response` 对象获取 - 提取数据中,可以提取响应中的 `token` 值,并赋值给变量 `token`。 - `token: [json, $.data.token, 0]` - `json`: `requests.Response` 对象的 `json()` 方法返回的字典 - `$.data.token`: `jsonpath` 表达式,用于提取 `token` 值, 或者正则表达式,`jsonpath` 表达式参考 https://jsonpath.com/, - 必须`$.`开头, `$`表示根节点。提取出来时`list`类型。 - `0`: 指示提取 token 值中的第 `0` 个值 ## Web UI测试用例 ### 运行环境 - 安装 `plawright` - `pip install playwright` - 安装 `chromium`, 默认为 `chromium` 浏览器,如需更换,修改`settings.json`,并参考 https://playwright.dev/docs/browsers - `playwright install chromium` ### 步骤模型类 ``` python class FuncStepModel(BaseModel): """ 函数步骤模型 function step model class """ name: str = Field('', description="步骤名称", alias='步骤名称') description: str = Field('', description="步骤描述", alias='步骤描述') func: str = Field(..., description="`PlayWrightUtil` 类中需要执行的函数", alias='函数名') args: Union[List, Tuple] = Field([], description="函数参数列表", alias='参数列表') kwargs: dict = Field({}, description="函数关键字参数字典", alias='参数字典') callback: Union[None, "FuncStepModel"] = Field(None, description="回调函数", alias='回调函数') ``` ### 用例模板 ``` yaml - 模块名称: 测试登录 UI名称: 登录 用例名称: 登录成功 用例描述: 用户名正确,密码正确,登录成功 是否运行: true 新窗口: true 窗口索引: 0 执行步骤: - 步骤名称: 打开百度页面 函数名: open 参数列表: [ 'https://www.baidu.com' ] 参数字典: { } 回调函数: null - 步骤名称: 等待页面加载完成 函数名: wait_for_timeout 参数列表: [ 2000 ] - 步骤名称: 点击新闻链接 函数名: click 参数列表: [ '#s-top-left > a:nth-child(1)' ] - 步骤名称: 等待页面加载完成 函数名: wait_for_timeout 参数列表: [ 2000 ] - 步骤名称: 切换至旧窗口 函数名: switch_to_page 参数列表: [ 0 ] - 步骤名称: 等待页面加载完成 函数名: wait_for_timeout 参数列表: [ 2000 ] - 步骤名称: 输入搜索内容 函数名: input 参数列表: [ '#kw', '15740525667' ] - 步骤名称: 点击搜索按钮 函数名: click 参数列表: [ '#su' ] - 步骤名称: 等待页面加载完成 函数名: wait_for_timeout 参数列表: [ 5000 ] 断言: - 断言方法: equal 实际值: 函数名: get_attribute 参数列表: [ '#su', 'value' ] 期望值: 百度一下 ``` ### 执行步骤, 实际值说明 > 函数名参考 [playwright_util.py](utils%2Fweb%2Fplaywright_util.py) 文件中的方法 | 函数名 | 参数列表 | 说明 | |------------------------|------------------------------------------------------------------------------------------------------------------------|--------------------------------| | page | | 获取当前页面对象 | | title | | 获取页面标题 | | reload | | 刷新页面 | | go_back | | 后退页面 | | go_forward | | 前进页面 | | open | `url: str ` | 打开浏览器,并访问指定 url | | click | `selector: str` | 点击 | | uncheck | `selector: str` | 取消选中 | | is_checked | `selector: str` | 判断是否选中 | | check | `selector: str` | 选中 | | input | `selector: str, value: str` | 在指定的元素中输入数据 | | input_files | `selector: str, files: Union[List[Union[Path, str]], Union[Path, str]]` | 设置文件上传 | | hover | `selector: str` | 鼠标悬停 | | focus | `selector: str` | 聚焦元素 | | type | `selector: str, value: str` | 输入文本内容 | | set_viewport_size | `width: int, height: int` | 设置视窗大小 | | switch_to_page | `index: Union[str, int]` | 切换到指定页面 | | locator | `selector: str` | 获取元素定位器 | | frame_locator | `selector: str` | 获取 frame / iframe 定位器 | | wait_for | `selector: str,state: Literal["attached", "detached", "visible", "hidden", "stable"] = 'visible',timeout: int = 30000` | 等待页面导航 | | wait_for_load_state | `selector: str,state: Literal["domcontentloaded", "load", "networkidle"] = 'load',timeout: int = 30000` | 等待页面加载状态 | | wait_for_timeout | `timeout: int` | 等待指定时间 | | wait_for_selector | `selector: str, timeout: int = 30000` | 等待元素出现 | | screenshot | `path: str = None, **kwargs ` | 截图并保存到文件,参考Page().screenshot() | | inner_text | `selector: str` | 获取元素内文本 | | all_inner_texts | `selector: str` | 获取元素列表内文本 | | inner_html | `selector: str` | 获取元素内 html | | text_content | `selector: str` | 获取元素文本内容 | | all_text_contents | `selector: str` | 获取元素列表文本内容 | | get_attribute | `selector: str, attribute: str` | 获取元素属性值 | | is_visible | `selector: str` | 判断元素是否可见 | | select_option | `selector: str, value: str` | 选择下拉框选项 | | select_option_by_index | `selector: str, index: int` | 选择下拉框选项 | | select_option_by_label | `selector: str, label: str` | 选择下拉框选项 | | select_option_clear | `selector: str` | 清空下拉框选项 | | drag_to | `selector: str, target: str` | 拖拽元素到目标元素 | | drag_and_drop | `source: str, target: str` | 拖拽元素到目标元素 | | evaluate | `expression: str` | 执行 js 表达式 | | evaluate_handle | `expression: str` | 执行 js 表达式 | | python_eval | `expression: str` | eval 表达式执行 python 代码 | | python_exec | `expression: str` | exec 表达式执行 python 代码 | | close | | 关闭浏览器窗口 | | close_context | | 关闭浏览器上下文 | ## 断言方式 > 目前支持的断言 > - 具体实现见,[utils/public/assert_util.py](utils%2Fpublic%2Fassert_util.py),在此模块下进行拓展 参数说明: ``` python from typing import Any from pydantic import BaseModel, Field class AssertDataModel(BaseModel): actual: Any = Field(alias='实际值') expected: Any = Field(None, alias='期望值') method: str = Field(alias='断言方法') message: str = Field(None, alias='断言消息') ``` | 断言方式 | 参数说明 | 函数说明 | |-----------------|-------------------------------------------------|---------------| | equal | actual: Any, expected: Any, message: str = None | 预期值等于实际值 | | not_equal | actual: Any, expected: Any, message: str = None | 预期值不等于实际值 | | is_true | actual: Any, message=None | 预期值为 True | | is_false | actual: Any, message=None | 预期值为 False | | is_none | actual: Any, message=None | 预期值是 None | | is_not_none | actual: Any, message=None | 预期值不是 None | | is_in | actual: Any, expected: Any, message=None | 预期值在实际值中 | | is_not_in | actual: Any, expected: Any, message=None | 预期值不在实际值中 | | is_instance | actual: Any, expected: Type, message=None | 预期值是实际值的实例 | | is_not_instance | actual: Any, expected, message=None | 预期值不是实际值的实例 | | is_json | actual: Any, message=None | 预期值是 json 格式 | | is_not_json | actual: Any, message=None | 预期值不是 json 格式 | | is_empty | actual: Any, message=None | 预期值为空 | | is_200 | actual: int, message=None | 响应状态码为 200 | ## 配置文件 > 配置文件位于项目根目录下的 `settings.json` 文件 > > 具体字段说明如下: > [setting.py](common%2F_models%2Fsetting.py) > > 在项目目录下运行 `python init.py` 即可生成配置文件 > 根据实际情况修改配置文件,默认配置如下: ``` json { "setting_path": "F:\\PythonObject\\auto-test-frame\\settings.json", "variables": "F:\\AppData\\variables", "auto_test_setting": { "project_name": "AutoTestProject", "tester_name": "Tester", "language": "zh-CN", "test_case_path": "F:\\PythonObject\\auto-test-frame\\test_cases", "allure_app_path": "F:\\PythonObject\\auto-test-frame\\AppData\\allure-2.30.0\\bin\\allure.bat", "case_type": "yml" }, "request_setting": { "timeout": 60, "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0" }, "browser_setting": { "browser": "chromium" }, "report_setting": { "report_dir": "F:\\PythonObject\\auto-test-frame\\AppData\\reports", "log_path": "F:\\PythonObject\\auto-test-frame\\AppData\\Log" }, "ding_ding_setting": { "access_token": "", "secret": "" }, "minio_setting": { "endpoint": "", "access_key": null, "secret_key": null, "secure": false, "bucket_name": "", "link_expires": 7 }, "wechat_setting": { "webhook": "" }, "email_setting": { "smtp_host": "smtp.163.com", "smtp_port": 465, "smtp_user": "13511111111@163.com", "smtp_password": "QJELFEHEDKGSRJJJ", "smtp_ssl": true, "receiver": [ "10086@qq.com" ] }, "msg_template": "\n## ${project_name} 自动化测试报告\n> 👤 测试人员: ${tester_name}\n> 🤖 测试结果: ${result}\n> ✅ 通过用例: ${passed}\n> 🔧 失败用例: ${failed}\n> ❌ 错误用例: ${error}\n> ⚠️ 跳过用例: ${skipped}\n> ⌛ 开始时间: ${started_time}\n> ⏱️ 执行耗时: ${elapsed}\n> ➡️ [查看详情](${link})\n" } ``` ## 贡献者 | 贡献者 | 贡献内容 | 链接地址 | |------|--------------------|--------------------------------------------------------| | 赤鸢仙人 | 接口测试用例编写、代码优化、文档编写 | [https://gitee.com/chiyaun](https://gitee.com/chiyaun) |