# pytest+yaml+allure+钉钉接口自动化测试,无需代码能力,小白也可使用 **Repository Path**: it-xiaobai-java/pytest-apitest ## Basic Information - **Project Name**: pytest+yaml+allure+钉钉接口自动化测试,无需代码能力,小白也可使用 - **Description**: pytest+yaml+allure的接口自动化测试框架 - 无序编写任意代码,自动生成用例代码: 纯小白也能使用 - 测试数据隔离, 实现数据驱动 - 支持多接口数据依赖: 提取返回内容,用于其他用例 - 数据库断言: 直接在测试用例中写入查询的sql即可断言,无需编写代码 - 动态多断言: 如接口需要同时校验响应数据和sql校验,支持多场景断言 - **Primary Language**: Python - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 9 - **Created**: 2025-03-04 - **Last Updated**: 2025-03-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README [TOC] # 使用pytest+yaml+allure的接口自动化测试框架 ### 前置条件 **Windows:** 1.安装python,python版本推荐小于3.10,安装requirements.txt 的库,pycharm会提示,然后安装即可,也可以通过pip安装,版本最好一致,不同版本可能不兼容 2.配置allure,建议使用框架中的2.17.3版本,将“allure-2.17.3\bin”配置为环境变量,配置后cmd控制台使用“allure --version”验证是否安装成功 3.支持pytest.ini中文需要修改“F:\ShunYunAutoTest\venv\lib\site-packages\iniconfig\\__init__.py”里面**52**的为: ```python # f = open(self.path) f = open(self.path, encoding="utf-8") ``` 4. jdk安装,建议1.8版本 **Linux:** 参考文件:centos7.6+python3+allure+selenium+jdk1.8安装配置.md 网页版:https://blog.csdn.net/weixin_45292690/article/details/130508470?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22130508470%22%2C%22source%22%3A%22weixin_45292690%22%7D 或者网上查下 1. 安装python,python版本推荐小于3.10,安装requirements.txt 的库,python教程参考 2. 配置allure,建议使用框架中的2.17.3tgz版本,将“allure-2.17.3\bin”配置为环境变量,安装参考 3. jdk安装,建议1.8版本,安装参考 ### 一.一个yaml文件一个接口 ### 二.用到的pytest插件: ​ pytest-html 生成简易报告 ​ pytest-xdist 多线程 ​ pytest-orderding 控制测试用例的执行顺序 ​ pytest-rerunfailures 失败用例重跑 ​ pytest-base-url 基础路径的配置 ​ allure-pytest 生成allure报告 ### 三.markers的使用 ​ 在用例上面加上: ```python @pytest.mark.smoke @pytest.mark.usermanage addopts = -v -s -m=smoke -p no:warnings --alluredir=./temps --clean-alluredir ``` ​ 在执行时需要在ini配置文件中加上: ​ -m 分组名 or 分组名 ​ 在执行时需要使用: ​ -m 分组名 or 分组名 ### 四.执行顺序 ```python @pytest.mark.run(order=1) ``` ### 五.前后置执行 在所有类,所有用例之前或之后 ```python def setup_class(self): print("在类之前的操作") def teardown_class(self): print("在类之后的操作") def setup(self): print("在所有用例之前的前置操作") def teardown(self): print("在所有用例之后的后置操作") ``` 希望在部分用例之前或之后执行。使用Fixture Fixture装饰器完整结构如下: ```python @pytest.fixture(scope="作用域",autouser="自动执行",params="数据驱动",ids="参数别名",name="fixture别名") ``` ```python @pytest.fixture(scope="function",params=return_list()) def mysql_test(request): """ 这个就放着,当参考例子的 这里的params用于传输数据(list,tuple,字典列表,字典元祖),需要在夹 具里面通过request(固定写法)接收,然后通过request.param(固定写法) 获取数据,然后再通过yield把数据返回到测试用例中,然后使用。 :param request: """ print(request.param) print("连接数据库") yield request.param print("关闭数据库连接") ``` 应用: 1.scope:标记fixture的作用域 function:函数级别(可以手动,也可以自动) class:类级别(一般是自动) module:模块级别(一般是自动) package/session:会话级别(一般是自动) 应用: 1.scope:标记fixture的作用域 function:函数级别(可以手动,也可以自动) class:类级别(一般是自动) module:模块级别(一般是自动) package/session:会话级别(一般是自动) ### 六.allure报告的用例的严重程度,可以加类或者方法上 例子: ```python @allure.severity(allure.severity_level.BLOCKER) ``` blocker:中断缺陷:致命bug:内存泄漏,用户数据丢失,系统奔溃。 critical:临界缺陷:严重bug:功能未实现,功能错误,重复提交 normal:一般缺陷,一般bug,条件查询有误,大数据了无响应等 minor级别:次要缺陷:提示bug,颜色搭配不好,字体排列不整齐,错别字。 trivial级别:轻微缺陷:轻微bug,没有使用专业术语,必填项无提示。建议。 ### 七、allure报告如何在本地访问。 因为pycharm自带容器。tomcat,Nginx,weblogic 1.在本地搭建本地服务器。 2.通过启动服务打开allure报告。 allure open ./reports/allures ### 八、接口自动化测试框架规则 ##### 1.必须有五个一级关键字:name、base_url、request、validate、assert_sql ##### 2.在request一级关键字下必须包含两个二级关键字:method、url ##### 3.传参方式:在request一级关键字下,二级关键字传参 ​ 如果是get请求,通过params传参 ​ 如果是post请求 ​ 传json格式:通过json关键字传参 ​ 传表单格式:通过data关键字传参 ​ 传文件格式:通过files关键词传参,路径需要"\\"进行转义,如: ​ files: ​ file_path: "D:\\test.jpg" ```yaml request: method: post url: /api/system/enterprise headers: {"Content-Type": "application/json;charset=utf-8","Authorization": "${get_extract_data(cs_token)}"} json: userName: $csv{userName} leader: "测试" phone: $csv{phone} password: "admin123" passwordConfirm: "admin123" enterpriseName: $csv{enterpriseName} regionName: "华南" address: "广东省中山市专治跌打损伤" logo: null nickName: "测试" phonenumber: $csv{phone} lat: 22.267916 lon: 113.485942 region: "2" method: "post" sysUser: nickName: "测试" phonenumber: $csv{phone} userName: $csv{userName} password: "" passwordConfirm: "admin123" ``` ```yaml request: method: post url: /adminManage/list headers: {"Content-Type": "application/json;charset=utf-8","Authorization": "${get_extract_data(login_token)}"} json: {"name":"","account":"","groupName":"","pageNo":1,"pageSize":15} ``` ##### 4.如果需要做接口关联的话,那一级关键字中必须要有:extract,目前支持正则匹配和jsonpath匹配,比如: ```yaml extract: user_Id795: '"userId":(.*?),' user_Id796: $..userId ``` ```json { "code": 0, "message": "success", "data": { "name": "超级管理员", "account": "ceshi1", "type": 0, "company": "绍兴处置中心", "mobile": "133333", "code": "ABCDEF", "token": "hkk-F4fkghsN", "groupId": "1,5,2,6,9,10,11,7,3,4,8", "jurisdiction": { "name": "超级管理员", "id": 1 }, "areaCode": 330600, "longitude": "120.65391", "latitude": "30.21213" } } ``` **提取变量到extract.yaml文件中:** jsonpath提取比如: ```yaml extract: login_message: $.message login_data_name: $..name ``` 正则提取比如: ```yaml extract: login_token: '"token":"(.*?)"' ``` ​ 一起用: ```yaml extract: login_message: $.message login_data_name: $..name login_token: '"token":"(.*?)"' ``` **从extract.yaml 文件中取值变量** 如: ```yaml login_token: "${get_extract_data(login_token)}" ``` ##### 5.热加载,当yaml中需要动态参数的时候,可以在debug_talk.py中写方法调用, 注意:定义的方法必须有参数;传参的时候,需要什么类型的时候,需要进行强转。int(min_number), int(max_number) 如: ##获取随机数 ```python def get_random_number(self, min_number, max_number): return random.randint(int(min_number), int(max_number)) ``` yaml中调用的写法: ```yaml password: ${get_random_number(100000,999999)} ``` ##### 6.此框架支持四种接口响应断言方式 分别为:contains、equals、time、jsonpath,除了jsonpath方式,其他的当值为纯数字的时候需要加英文状态的引号。 contains:用于包含情况断言 equals:完全相等情况断言。且其中包含响应状态码断言,使用方式为:{status_code: 200} time: 响应时间断言,填入时间即可,单位为ms,无需加单引号 jsonpath:1.path为提取实际响应内容的值 2.type为in的时候是期望值在实际值中,type为"=="的时候是期望值完全等于实际值 3.value 为期望值;jsonpath 已经支持热加载,可以直接调用方法 ​ 如: ```yaml validate: - equals: {status_code: 200} # 状态码断言 - equals: {message: success} # 响应内容完成相等的断言 - equals: {code: 0} # 响应内容完成相等的断言 - contains: token # 包含断言 - contains: "'code': 500" # 包含断言 - contains: '500' - time: 500 #大于500ms,断言失败 - jsonpath: path: $.data.user.providerId #提取实际响应内容的值 type: in #断言方式,包含 type: == #断言方式,完全相等 value: 59 #期望值 value: "${get_api_info(provider_id)}" # 热加载 ``` ##### 7.csv数据驱动使用一级关键字parameters,二级关键字中各变量名使用“-”分隔,使用$csv{}调用 ​ 如: ​ yaml文件中: ```yaml parameters: name-account-password-assert_str: /handle/login/login.csv parameters: name: $csv{name} json: account: $csv{account} password: $csv{password} ``` ​ csv文件中: ```csv name,account,password,assert_str 处置平台输入正确的账号密码登录,ceshi1,123456,token account必填项检查,"",123456,账号不能为空 password必填项检查,ceshi1,"",密码不能为空 测试登录输入错误密码,ceshi1,cuowudemima,账号或密码错误 ``` 注意事项: csv文件中写入规范:当测试输入空的时候使用两个英文状态的双引号,请勿使用中文状态的,中文的算作输入了双引号的值了 断言只能使用contains断言,可以多个的 ##### 8.日志监控和异常处理以及基础路径的设置 ##### 9.allure报告定制 ```python @allure.epic("项目名称:云服务接口自动化测试项目") @allure.feature("模块名称:个人信息相关模块") class TestEmployeeManagement: @allure.story("接口名称:获取个人信息信息") @pytest.mark.parametrize("args", YamlUtil.read_testcase_yaml("/cs_imotorlinx/mine/test_employee_management/get_employee_info.yaml")) def test_get_employee_info(self, args): allure.dynamic.title("测试用例标题:{}".format(args['name'])) RequestUtil().analysis_yaml(args) ``` ##### 10. 数据库断言 assert_sql 关键字不管是否使用都需要在的 sql_statement:放sql语句,因为是用于断言的,所以只支持查询的,返回的内容为,格式为字符串: ```python [{'user_id': 342, 'enterprise_id': 170, 'provider_id': None, 'dept_id': None, 'user_name': 'siyueqiye', 'nick_name': 'siyueqiye', 'user_type': 2, 'email': None, 'phonenumber': '177*******', 'sex': '0', 'avatar': None, 'password': '$2a$10$jVJurAhzWibCY4pEEUMDvOKjn6VJwiVpJ46nk.bIm4WngTCA93fvm', 'salt': None, 'status': '0', 'del_flag': '0', 'del_version': 0, 'login_ip': None, 'login_date': None, 'manager_id': None, 'create_by': 'admin', 'create_time': datetime.datetime(2022, 5, 6, 11, 5, 15), 'update_by': None, 'update_time': datetime.datetime(2022, 5, 17, 10, 35, 36), 'remark': None}] ``` yaml文件的写法如下 ```yaml assert_sql: - sql_statement: SELECT * FROM `imotor`.`sys_user` WHERE `phonenumber` LIKE '%177*******%' LIMIT 0, 1000 - sql_assert: "'user_id': 342, 'enterprise_id': 170" - sql_reserve: "'user_id': 342, 'enterprise_id': 170" - state: all - switch: True ``` sql_assert 中是预期结果是否在实际结果里面,目前的写法格式必须为:"'字段1':'字段value'" sql_reserve 中是预期结果是否不在实际结果,一般用于硬删除的时候,目前的写法格式必须为:"'字段1':'字段value'" 注意: ​ 输入都需要英文状态的 ​ 非数字需要用单引号、数字的时候不要单引号、sql里面的内容必须是连着的 ​ 数据库某一个字段的内容为“null”的时候,python返回的时候是“None”,填写预期结果需注意 ​ 当查询出的内容没有内容的时候,python返回的是“()”,所以预期结果就填写“()” ​ state字段不存在的时候或者state的值为“all”的时候查询全部的数据,其他情况都是查询单条 ​ switch 为 True 执行数据库判断,False表示不进行数据库断言 ##### 11.自动生成代码的yaml文件编写规范 ```yaml - name: 云服务获取个人信息 case_common: allureEpic: 云服务平台接口 allureFeature: 个人信息模块 allureStory: 获取个人信息接口 base_url: ${get_base_url(url_cs_imotorlinx)} request: method: get url: /api/system/user/list?pageNum=1&pageSize=1000 headers: {"Content-Type": "application/json;charset=utf-8","Authorization": "${get_extract_data(cs_token)}"} validate: - contains: 操作成功 assert_sql : - sql_statement: SELECT * FROM `imotor`.`sys_user` WHERE `phonenumber` LIKE '%177*******%' LIMIT 0, 1000 - sql: "'user_id': 342" - name: 云服务获取个人信息,错误的url base_url: ${get_base_url(url_cs_imotorlinx)} request: method: get url: /api/system/user/list1?pageNum=1&pageSize=1000 headers: {"Content-Type": "application/json;charset=utf-8","Authorization": "${get_extract_data(cs_token)}"} validate: - contains: "500" assert_sql: - sql_statement: SELECT * FROM `imotor`.`sys_user` WHERE `phonenumber` LIKE '%177*******%' LIMIT 0, 1000 - sql: "'user_id': 342" - sql: "'enterprise_id': 17" - state: one ``` **加上case_common(必填**),当一个yaml有多个文件的时候,在第一个用例中填写: ```yaml case_common: # 测试项目名称 allureEpic: 云服务平台接口 # 接口相关模块 allureFeature: 个人信息模块 # 接口名称 allureStory: 获取个人信息接口 ``` ##### 12.智能等待时间的使用 在用例文件中增加一级关键字"wait_time",会在断言之前增加等待时间(单位:秒),防止响应过慢接口导致接口失败,使用方法如下: ```yaml - name: 测试用例名称001 wait_time: 1 ``` ##### 13.测试用例跳过的使用 在用例文件增加一级关键字“is_run”,当值为“False”的时候,跳过该用例,没该关键字或其他值的时候,跳过该测试用例 ```yaml - name: 获取24小时高报设备台数(/imotor/device/apumStatisticsTwentyFour)--用例编号812 #是否跳过测试用例 is_run: is_run: False ``` ##### 14.钉钉推送配置 钉钉机器人配置: 1. 新建群聊--添加机器人--选择自定义机器人--"安全设置"选择"自定义关键词"--输入"测试"--完成机器人添加,得到webhook 2. 将webhook的值,填入框架的"config.yaml"的"webhook" 中 ##### 15.前置和后置操作 前置操作:用于当前测试用例执行之前的操作,比如通过sql将需要的值写入extract.yaml文件中,或者一些其他的前置操作,需要关键字“setup”,然后去调debug_talk.py中的方法 后置操作:用于当前测试用例执行之前的操作,比如对用例新增、编辑的操作进行还原删除操作,需要关键字“teardown”,然后去调debug_talk.py中的方法 ```yaml # 后置操作 setup: sql_extract: ${extract_sql(SELECT id FROM `imotor`.`m_report_rule` WHERE rule_name like '%接口自动化测试%'ORDER BY id DESC LIMIT 1,sql_id_1038)} # 后置操作 teardown: sql_teardown: ${extract_sql(SELECT id FROM `imotor`.`m_report_rule` WHERE rule_name like '%接口自动化测试%'ORDER BY id DESC LIMIT 1,sql_id_end_1038)} ``` ### 八.config.yaml文件介绍 ```yaml project: name: PytestApi author: 搬砖客 url: url_big_background: http://8.1:8888 url_iot_platform: http://39.:8080 url_imotor_ev: http://rdc-dx.com url_imotor_prod: https://im.cn url_imotor_dev: https://w.cn url_imotor: https://web-px.cn nginx_url: /imotor-api # ding_Webhook:钉钉机器人的webhook ding_Webhook: https://oapi.dingtalk.com/robot/send? # conftest中的账号密码配置 login: username: provin password: eL0hvAfgEIHDGJWw== password_selenium: 2 # 日志配置 log: user_name: xzk file_name: test.log when: S interval: 1 backup: 10 console_level: INFO file_level: DEBUG # pattern: '%(module)s - %(funcName)s - %(lineno)d - %(asctime)s - %(name)s - %(levelname)s - %(message)s' pattern: '%(levelname)s %(asctime)s [%(name)s] [%(filename)s(%(funcName)s:%(lineno)d)] - %(message)s' # 数据库配置 mysql: host: 8.4.233 user: root password: Imotor@2022 database: imotor port: 3306 # 配置jenkins的ip host: localhost: 127.0.0.1 jenkins_host: 121.210 # 配置jenkins的port port: jenkins_port: 8080 localhost: 8080 # sql和dingTalk的值为True的时候表示开启数据库断言和开启钉钉通知 switch: sql: True dingTalk: False # 实时更新用例内容,False时,已生成的代码不会在做变更 # 设置为True的时候,修改yaml文件的用例,代码中的内容会实时更新 real_time_update_test_cases: True # enable为True表示生成测试报告,type为“local”表示本地windows跑,jenkins表示jenkins跑 report: enable: True type: local ``` ### 九.如何使用 ##### 1.data里面放测试用例 ##### 2.自动生成测试代码的使用 ​ 文件路径:common/readFileUtils/caseAutomaticControl.py ​ 执行该py文件即可,前提是data中有相应的代码 ##### 3.conftest.py的使用 ​ 把需要登录的操作,提取全局token的时候写在这边,不要去使用yaml文件 ​ conftest.py理解为一个专门存放fixture的配置文件。 ​ **conftest.py的优势** ​ 当多个test.py同时需要使用一个前置条件,比如登录功能,此时,登录功能不能存放在某一个py中。 ​ conftest.py可以完美解决上面问题,能够单独对fixture进行管理。 ​ **conftest.py配置文件的注意事项:** ​ conftest.py命名是固定的,不可改变。 ​ pytest会默认执行conftest.py中的fixture。 ​ conftest.py只对同个目录下的py生效。 ​ 每个目录都可以有自己的conftest.py文件,一个项目中可以拥有多个conftest.py文件。 ​ 执行测试用例时,conftest.py不用手动导入。 ##### 4.执行脚本 ​ **run_main.py** 按照文件中的注释使用即可,后续会优化 ##### 5.报告地址 window本地:report/index.html jenkins:allure-report/index.html ### 十.实现功能 - 测试数据隔离, 实现数据驱动 - 支持多接口数据依赖: 提取返回内容,用于其他用例 - 数据库断言: 直接在测试用例中写入查询的sql即可断言,无需编写代码 - 动态多断言: 如接口需要同时校验响应数据和sql校验,支持多场景断言 - 自动生成用例代码: 测试人员在yaml文件中填写好测试用例, 程序可以直接生成用例代码,纯小白也能使用 - 返回接口的运行时长 - 支持单个测试用例的前置和后置操作 - 日志模块: 打印每个接口用例的日志信息 - 通知: 目前支持钉钉通知 - 自定义拓展字段: 如用例中需要生成的随机数据,可直接调用 - 兼容linux和windows ### 十一.后续优化 1.数据库断言(已完成,可优化) 2.代码自动生成,已完成 3.钉钉或者邮件发送,已经加了钉钉通知 4.jenkins集成,在linux跑的时候这个有点问题,找找问题还得-优先级4--已完成 5.增加提取数据库返回内容到extract文件中的功能--待完成-优先级3 6.数据库断言需要支持热加载(已完成) 7.接口断言、提取增加或改为jsonpath(已完成,加了热加载) 8.录制脚本--待完成(使用mitmproxy)-优先级4 9.数据库断言改为jsonpath-优先级2 10.代码注释、编写规范 完善--进行中 11.日志优化--待完成-优先级3 12.支持swagger接口文档转成yaml用例--待完成-优先级4 13.老的接口响应断言加上热加载-优先级1 14.多线程执行(待完成,可以使用 pytest-xdist)-优先级2 15.批量修改yaml文件内容(待完成),完成后将"assert_sql" 改为"assert_sql",相关代码适配-优先级2 16.多数据库连接。思路:在每个项目中建conftest文件,进行各自的数据库连接和断开 2.各平台的接口必须写在相应的文件夹内,因为根据用例来连接数据库和断开,容易被封ip 17.自动生成代码,后面也要加开关(在run_main.py中读取配置文件)-优先级3 18.extract提取需要支持jsonpath格式---已完成