Python 接口测试框架

目录结构定义

首先来看一下项目整体的结构

框架结构

代码结构

Excel 文件结构

代码详细解析

1.工具包 tools

封装操作 excel 方法 excel_operation.py

import xlrd
from config.config import PROJECT_PATHclass OperationExcel:def __init__(self, file_name=None, sheet_id=0):if file_name:self.file_name = PROJECT_PATH + '/data/' + file_nameself.sheet_id = sheet_idelse:try:self.file_name = PROJECT_PATH + '/data/case.xlsx'self.sheet_id = 0except FileExistsError:raise FileExistsError("the default testcase file not found")self.book = self.get_book()self.data = self.get_data()# 获取工作簿def get_book(self):book = xlrd.open_workbook(self.file_name)return book# 获取 sheets 的内容def get_data(self):book = self.booktables = book.sheets()[self.sheet_id]return tables# 获取所有 sheet 的名字def get_sheet_name(self):book = self.bookreturn book.sheet_names()# 获取所有 sheetsdef get_sheets(self):book = self.booksheets = book.sheets()return sheets# 获取某个单元格的内容def get_cell_value(self, row, col):return self.data.cell_value(row, col)# 获取单元格的行数def get_lines(self):tables = self.datacase_rows = tables.nrows - 1return case_rows# 获取某一列的内容def get_cols_data(self, col_id=None):if col_id is not None:cols = self.data.col_values(col_id)else:cols = self.data.col_values(0)return cols# 获取某一行的内容def get_rows_data(self, row_id=None):if row_id is not None:rows = self.data.row_values(row_id)else:rows = self.data.row_values(0)return rows# 获取某个 caseid 对应的行号def get_row_num(self, case_id):num = 0cols_data = self.get_cols_data()for col_data in cols_data:if case_id in col_data:return numnum += 1

使用 xlrd 库来操作 excel,同时,该类只做最底层的 excel 数据提取,不做任何业务相关的判断。后面会陆续增加 json,yaml 等数据结构的操作工具。

中间数据操作层 operate_data.py

from config.config import ExcelConfDataclass OperateExcelData(object):def get_caseid(self):return ExcelConfData.caseiddef get_url(self):return ExcelConfData.urldef get_method(self):return ExcelConfData.methoddef get_is_auto_run(self):return ExcelConfData.automateddef get_header(self):return ExcelConfData.headerdef get_data(self):return ExcelConfData.datadef get_casename(self):return ExcelConfData.casenamedef get_statuscode(self):return ExcelConfData.statuscodedef get_checkpoints(self):return ExcelConfData.checkpointsdef get_validate(self):return ExcelConfData.validatedef get_caseuniqueid(self):return ExcelConfData.caseuniqueiddef get_authtype(self):return ExcelConfData.authtype

属于操作数据的中间层,从配置文件中拿到我们定义好的 excel 结构,这样,如果我们的 excel 结构有变化,只需要修改配置文件即可

配置文件中的 excel 结构如下

class ExcelConfData:caseid = '0'casename = '1'caselevel = '2'preconditions = '3'testcontent = '4'expect = '5'casecategory = '6'automated = '7'  # 1 是自动运行, 2 是非自动运行caseuniqueid = '1'  # 8method = '9'url = '10'data = '11'header = '12'statuscode = '13'checkpoints = '14'validate = '15'parameterize = '16'result = '17'authtype = '18'  # 0:admin, 1:common user, 2:not login

获取测试文件中数据工具 get_data.py

from tools.excel_operation import OperationExcel
from tools.operate_data import OperateExcelDataclass GetExcelData(object):def __init__(self, filename=None, sheet_id=0):self.operate_excel = OperationExcel(filename, sheet_id)self.operate_data = OperateExcelData()# 获取 sheet 个数def get_sheets(self):sheet_num = self.operate_excel.get_sheets()return len(sheet_num)# 获取 excel 行数,即用例个数def get_case_lines(self):return self.operate_excel.get_lines()# 获取是否执行def get_is_auto_run(self, row):auto_flag = Falsecol = int(self.operate_data.get_is_auto_run())run_model = self.operate_excel.get_cell_value(row, col)if run_model == 1:auto_flag = Trueelse:auto_flag = Falsereturn auto_flag# 获取请求方式def get_request_method(self, row):col = int(self.operate_data.get_method())request_method = self.operate_excel.get_cell_value(row, col)return request_method# 获取 urldef get_request_url(self, row):col = int(self.operate_data.get_url())url = self.operate_excel.get_cell_value(row, col)return url# 获取请求数据def get_request_data(self, row):col = int(self.operate_data.get_data())data = self.operate_excel.get_cell_value(row, col)return data# 获取 status codedef get_response_statuscode(self, row):col = int(self.operate_data.get_statuscode())statuscode = self.operate_excel.get_cell_value(row, col)return statuscode# 获取 checkpointsdef get_checkpoints(self, row):col = int(self.operate_data.get_checkpoints())checkpoints = self.operate_excel.get_cell_value(row, col)return checkpoints# 获取 validatedef get_validate(self, row):col = int(self.operate_data.get_validate())validate = self.operate_excel.get_cell_value(row, col)return validate# 获取测试用例唯一 IDdef get_caseuniqueid(self, row):col = int(self.operate_data.get_caseuniqueid())caseuniqueid = self.operate_excel.get_cell_value(row, col)if isinstance(caseuniqueid, float):caseuniqueid = int(caseuniqueid)return str(caseuniqueid)# 获取 header 信息def get_header(self, row):col = int(self.operate_data.get_header())header = self.operate_excel.get_cell_value(row, col)return header# 获取是否需要鉴权信息def get_authtype(self, row):col = int(self.operate_data.get_authtype())authtype = self.operate_excel.get_cell_value(row, col)return authtype  

获取到测试数据中业务相关的数据,例如是否自动化执行,是否使用 header,是否需要鉴权信息等。

通用工具文件 common_util.py

import json
import operator
from config.config import UserInfo, EnvConf
import requestsclass CommonUtil(object):def is_contain(self, str1, str2):""":param str1: 原始字符串:param str2: 被查找的字符串:return: True or False"""flag = Noneif str1 in str2:flag = Trueelse:flag = Falsereturn flagdef is_equal_dict(self, d1, d2):if isinstance(d1, str):d1 = json.loads(d1)if isinstance(d2, str):d2 = json.loads(d2)return operator.eq(d1, d2)def adminlogin():url = f"http://{EnvConf.host}:{EnvConf.port}/api/user-management/tokens"data = UserInfo.admininforesp = requests.post(url=url, json=data)try:token = f"Bearer {resp.json()['data']['access_token']}"except:raisereturn tokendef commonlogin():url = f"http://{EnvConf.host}:{EnvConf.port}/api/user-management/tokens"data = UserInfo.commoninforesp = requests.post(url=url, json=data)try:token = f"Bearer {resp.json()['data']['access_token']}"except:raisereturn token

主要编写一些验证器,或者通用的获取登陆 token 信息等函数。这里的验证器还很简单,后面再慢慢添加,比如正则校验,解析 json 校验等。

2. 基础包 base

封装 http 请求 runmethod.py

import requests
import jsonclass RunMethod(object):def __init__(self):self.verify = Falseself.headers = Nonedef post_main(self, url, data=None, header=None):res = Noneif header is not None:res = requests.post(url=url, data=data, headers=header)else:res = requests.post(url=url, data=data)return res.json()def get_main(self, url, data=None, header=None, param=None):res = Noneif header is not None:res = requests.get(url=url, data=data, headers=header, verify=self.verify, params=param)else:res = requests.get(url=url, data=data, verify=self.verify, params=param)return res.json()def del_main(self, url, data=None, header=None):res = Noneif header is not None:res = requests.delete(url=url, data=data, headers=header)else:res = requests.delete(url=url, data=data)return res.json()def run_main(self, method, url, data=None, header=None):res = Noneif method == 'POST':res = self.post_main(url, data, header)elif method == 'GET':res = self.get_main(url, data, header)else:res = self.del_main(url, data, header)return json.dumps(res, ensure_ascii=False, sort_keys=True, indent=2)

当前的封装还是很简陋的,并没有过多的异常处理,参数校验等,后面会对这方面做一下增强。

runmock.py 是用来做 mock 数据的,以后再用。

提取 excel 数据文件 basetest.py

from tools.get_data import GetExcelData
from base.runmethod import RunMethod
from tools.common_util import CommonUtil
from config.config import EnvConf, Header
import json
from tools.excel_operation import OperationExcel
from tools.common_util import adminlogin, commonloginclass CaseDataAllSheets:def __init__(self, filename=None):self.filename = filenameself.opera_excel = OperationExcel(filename)self.sheet_nums = self.opera_excel.get_sheets()def get_all_sheets_data(self):total_data = {"sheet-data": [],'case_data_ids': []}for i in range(len(self.sheet_nums)):data = {}sheet_name = self.opera_excel.get_sheet_name()[i]casedata = CaseData(filename=self.filename, sheet_id=i)test_data, case_data_ids = casedata.get_testcase_data()data[sheet_name] = test_datatotal_data['sheet-data'].append(data)total_data['case_data_ids'].append(case_data_ids)return total_dataclass CaseData:def __init__(self, filename=None, sheet_id=0):self.exceldata = GetExcelData(filename, sheet_id)self.casenums = self.exceldata.get_case_lines()def get_testcase_data(self):test_data = {'parameterize': []}case_data_ids = []for case in range(1, self.casenums + 1):if self.exceldata.get_is_auto_run(case):case_data_json = {'request-data': {},'response-data': {}}case_method = self.exceldata.get_request_method(case)data_url = self.exceldata.get_request_url(case)case_url = f"http://{EnvConf.host}:{EnvConf.port}" + data_urlcase_data = self.exceldata.get_request_data(case)if case_data != '':try:case_data = json.loads(case_data)except:raisecase_header = self.exceldata.get_header(case)if case_header == '':case_header = Header.headerselse:try:case_header = json.loads(case_header)except:raisecase_statuscode = self.exceldata.get_response_statuscode(case)case_checkpoint = self.exceldata.get_checkpoints(case)case_validate = self.exceldata.get_validate(case)case_uniqueid = self.exceldata.get_caseuniqueid(case)print(case_uniqueid)print(type(case_uniqueid))case_authtype = self.exceldata.get_authtype(case)if case_authtype == 0:token = adminlogin()case_header['authorization'] = tokenelif case_authtype == 1:token = commonlogin()case_header['authorization'] = tokenelse:passcase_data_json['request-data']['url'] = case_urlcase_data_json['request-data']['data'] = case_datacase_data_json['request-data']['header'] = case_headercase_data_json['request-data']['method'] = case_methodcase_data_json['response-data']['statuscode'] = case_statuscodecase_data_json['response-data']['checkpoint'] = case_checkpointcase_data_json['response-data']['validate'] = case_validatecase_data_ids.append(case_uniqueid)test_data['parameterize'].append(case_data_json)return test_data, case_data_ids

我把真正的处理 excel 测试用例数据的功能放在了这里,将我们需要的数据,如:url,请求体 data,请求方法 method 等信息组装好,放到内存中,供 pytest 参数化时使用。

3. pytest 测试用例代码

在 case 文件夹中,用来存放真正的 pytest 测试代码,我们写一个简单的测试代码 demo

from base.basetest import BaseTest, CaseData
import pytestclass Test_example(BaseTest):testcase = CaseData('test.xlsx', 1)testdata, ids = testcase.get_testcase_data()@pytest.mark.parametrize('autotest', testdata['parameterize'], ids=ids)def test_case(self, autotest, casefile):res_json = self.runmethod.run_main(autotest['request-data']['method'], autotest['request-data']['url'],data=autotest['request-data']['data'],header=autotest['request-data']['header'])print(res_json)print("casefile", casefile)assert self.validate.is_equal_dict(res_json, autotest['response-data']['checkpoint']) is True

这里时获取 excel 中的 sheet 序号为1的内容来作为测试数据,如果我们需要把 excel 中所有 sheet 中的数据都作为测试数据来供 pytest 参数化的话,那么就可以实例化 CaseDataAllSheets 类。

4. 测试执行

最后,我们在 main.py 中运行 pytest 主程序

if __name__ == '__main__':import pytestpytest.main(['-s', '-q', '-vv', '--html=./report/report.html', '--self-contained-html'])

使用一个 report 插件来自动产生测试报告。

至此,我们以后只需要编写易于操作的 excel,而几乎不需要动任何 Python 代码,就能完成一次接口自动化测试了。当然,编写好的 excel 要放到 data 文件夹下哦!

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/498836.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【精选】Java项目介绍和界面搭建——拼图小游戏 中

🍬 博主介绍👨‍🎓 博主介绍:大家好,我是 hacker-routing ,很高兴认识大家~ ✨主攻领域:【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 🎉点赞➕评论➕收藏 …

项目解决方案: 实时视频拼接方案介绍

目 录 1、实时视频拼接概述 2、适用场景 3、系统介绍 3.1拼接形式 3.1.1横向拼接 3.1.2纵向拼接 3.2前端选择 3.2.1前端类型 3.2.2推荐配置 3.3后端选择 3.3.1录像回放 3.3.2客户端展示 4、拼接方案介绍 4.1基于4K摄像机的拼接方案 4.1.1系统架构…

贪心算法练习day2

删除字符 1.题目及要求 2.解题思路 1)初始化最小字母为‘Z’,确保任何字母都能与之比较 2)遍历单词,找到当前未删除字母中的最小字母 3)获取当前位置的字母 current word.charAt(i); 4)删…

vue3编写H5适配横竖屏

具体思路如下&#xff1a; 1、监听浏览器屏幕变化&#xff0c;通过监听屏幕宽高&#xff0c;辨别出是横屏&#xff0c;还是竖屏状态 在项目的起始根页面进行监听&#xff0c;我就是在App.vue文件下进行监听 代码如下&#xff1a; <template><RouterView /> <…

C语言数据结构基础—单链表相关数据结构题目6道

上一篇博客中&#xff0c;我们大致的讲解了单链表相关的各种接口。接下来我们通过例题来运用类似的思想&#xff0c;达到学以致用的目的。 1.移除链表元素 203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; 没有说明头结点是什么&#xff0c;默认就是第一个元素&am…

python_可视化_交互_多条线段点击高亮显示

需求 使用matplotlib 绘制折线图 响应鼠标事件 单击折线 线条高亮显示 解决方法: 使用 mplcursors 库, 一句代码可实现. 代码 import matplotlib.pyplot as plt import mplcursors import numpy as np# 生成一些示例数据 x np.linspace(0, 10, 100) y np.sin(x)# 创建绘图…

Python复合型数据避坑指南

目录 前言 列表&#xff08;Lists&#xff09; 1. 修改可变对象 2. 浅拷贝和深拷贝 元组&#xff08;Tuples&#xff09; 集合&#xff08;Sets&#xff09; 字典&#xff08;Dictionaries&#xff09; 1. 键值唯一性 2. 键的类型 实际应用场景 1. 数据分析与清洗 2. 网络…

记忆化搜索(Function,天下第一)

Function 这是一道很直观的递归题目&#xff0c;但是使用递归会导致时间超限&#xff0c;所以需要使用记忆化搜素。 首先把坑点讲一下&#xff1a;出题人会给出负数&#xff0c;而我们知道数组下标是不能有负数的&#xff0c;如果是二维数组还可以用map数组进行储存&#xff0c…

DETR(1):论文详解

文章目录 1. DETR 模型结构2.损失函数2.1 预测结果和GT 的匹配2.2 训练的loss计算3.实验3.1 大物体表现效果好3.2 Transformer Encoder 和Decoder的作用3.3 object query4. 伪代码5. 结论

Python set 集合

Python 集合 集合&#xff08;set&#xff09;是一个无序的不重复元素序列。 集合中的元素不会重复&#xff0c;并且可以进行交集、并集、差集等常见的集合操作。 可以使用大括号 { } 创建集合&#xff0c;元素之间用逗号 , 分隔&#xff0c; 或者也可以使用 set() 函数创建…

width:100%和width:auto有啥区别

项目中使用了with属性&#xff0c;突然好奇auto 和 100% 的区别&#xff0c;特地搜索实践总结了一下观点 一、 width属性介绍二、 代码带入三、 分析比较四、 总结 一、 width属性介绍 width 属性用于设置元素的宽度。width 默认设置内容区域的宽度&#xff0c;但如果 box-siz…

皇冠测评:网络电视盒子哪个品牌好?电视盒子排行榜

欢迎各位来到我们的测评频道&#xff0c;本期我们要分享的产品是电视盒子&#xff0c;因很多网友留言不知道网络电视盒子哪个品牌好&#xff0c;我们通过为期一个月的测评后整理了电视盒子排行榜&#xff0c;想买电视盒子的可以看看下面这五款产品&#xff0c;它们各方面表现非…